Fork me on GitHub
#beginners
<
2021-01-13
>
Zaymon01:01:35

Is https://github.com/dakrone/clj-http the preferred http client? Just for basic requests / polling / API exploration? New to Clojure I don’t know what the go to libraries are yet

Zaymon01:01:56

Or would http-kit be a better choice>

didibus01:01:15

I'd say the "most common default" one is Jetty with Ring: https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter

didibus01:01:28

Oh sorry, HTTP Client?

didibus01:01:01

Hum, either or, if its just for basic requests / polling / API exploration I'd go with HTTP Kit client personally, because its got zero dependencies. clj-http brings a lot of dependencies.

Zaymon01:01:24

Sounds good to me. Thanks! @U0K064KQV

hiredman02:01:35

The built in java http client is pretty good. I would recommend clj-http over http kit, especially for exploratory stuff to avoid having to decide how you are going deal with multiple threads

didibus02:01:32

@hiredman What do you mean? This is all you need to do:

(require '[org.httpkit.client :as http-client])
@(http-client/get "")

hiredman02:01:24

You are queuing up work to happen on another thread and then waiting for it, which is not the same as doing it on the same thread.

hiredman02:01:21

At the very least you have this global httpkit thread spinning doing work, which it will continue regardless of what happens to your thread

didibus02:01:02

I don't really see the issue...

seancorfield03:01:07

We mostly use clj-http at work but there are a couple of places where we need to be able to cancel HTTP requests after a fixed timeout period and we use http-kit's client for that since clj-http doesn't seem to have a way to do that (and we're using an old version of clj-http because recent version break some things in our tests).

seancorfield03:01:37

I like the simplicity of http-kit's client, but hiredman's point is important.

didibus03:01:21

For exploration that default seems fine, and then if you need to become much more serious, it lets you specify your own.

didibus04:01:21

Also, from peeking at the impl of http-kit, the client seems to multiplex NIO, so there's only one thread doing the request, the thread-pool is for your handlers.

dharrigan05:01:54

I've been using clj-http with great success, very easy to use.

hiredman07:01:32

to be clear, I am not saying don't use http kit, or that there is something wrong with http kit, it just would not be my first choice for fiddling around. if I wanted some with no dependencies I would use the http client that comes with java, if I wanted something to use without thinking too much about it I would use clj-http

aratare05:01:37

Hi there. I've come across tap> and am not sure when and where it should be used. From the Clojure release note, it's said that: > tap is a shared, globally accessible system for distributing a series of informational or diagnostic values to a set of (presumably effectful) handler functions. It can be used as a better debug prn, or for facilities like logging etc. But how is tap> any different from, say, normal logging? Thanks in advance 🙂

seancorfield05:01:11

It isn't intended for logging but it is awesome for debugging.

seancorfield05:01:41

Tools like REBL, Reveal, and Portal all "listen" for tap>'d values and display them.

seancorfield05:01:19

(funnily enough, I just gave a talk to London Clojurians today that featured tap> and I talked about it -- the recording should be up soon)

👍 3
aratare05:01:53

Looking forward to it. Thanks 🙂

seancorfield05:01:55

The great thing about tap> is that you can leave it in your (production) code and the attach and detach various listeners (using add-tap and remove-tap).

jaihindhreddy09:01:48

Assuming there are no add-tap calls that do bad things, right?

seancorfield17:01:58

Right. I was assuming no tap listeners (except when debugging).

aratare06:01:14

Ah I see. So unlike typical (println value), tap> allows you to dynamically configure how value will be handled based on which tap you're attaching, so, say, you may have a tap to print a full value in dev but a different tap to print only important bits in test. Am I getting close?

seancorfield06:01:12

Not quite. All tap>'d values go to all listeners, but the important part is that those listeners get data so they can choose to display it graphically, or in a table, or whatever.

seancorfield06:01:05

But each tap listener can decide what to do with each value, based on its structure.

seancorfield06:01:30

You can (add-tap println) and get the same regular printed output, or (add-tap prn) to get readable printed output, or (add-tap some-graphical-ui) to display data in a GUI. Take a look at https://github.com/vlaaad/reveal/ to see the sort of things that you can do with tap> output.

aratare06:01:12

That's handy. Now I see how one would want to use it over normal println. Thanks a lot for the explanation :D

pinealan08:01:30

how would you do fetch in clojurescript? is https://github.com/r0man/cljs-http a de facto client? or would you just use the fetchAPI or axios?

1
roelof09:01:31

A late good morning all

Christian09:01:41

Maybe this is more of a beginner question?

roelof09:01:49

first question of the day. If I want to ask a api several times to keep all the responses can I then do (let [answer] (repeat 3( slurp ........))) ?

popeye10:01:51

I am running below code and getting unable to resolve jj , Does if-let not consider else?

(if-let [jj (false? false)]
           (println "as")
           (println jj))

simongray10:01:35

(defmacro if-let
  "bindings => binding-form test

  If test is true, evaluates then with binding-form bound to the value of 
  test, if not, yields else"
  ....)
so no, it doesn’t bind in the else clause.

simongray10:01:14

but what’s the point of binding it? You already know the answer. It’s falsy.

popeye10:01:13

This is just a sample code, In production code I am assigning values

simongray10:01:28

If you need the value afterwards then bind it in a let and check the value in a regular if.

popeye10:01:06

yeah, I tried that first .. but wanted to reduce code so done for if-let

roelof10:01:15

it should but right now I cannot check it. I see a message on the last line that jj is not known

Christian10:01:32

it's only known in the true line:

(if-let [jj (true? false)]
  (println jj)
  (println "as"))

3
bnstvn14:01:08

is there a comfortable way of inspecting interim values inside threading macros? i mean something better than (->> 2 (#(doto % tap> )) (* 3))

Alex Miller (Clojure team)14:01:56

we're going to add one in 1.11 :) tap-> :)

💯 15
bnstvn14:01:35

thanks! that was fast! 🙂

Stuart14:01:30

Cool! I normally just write a little debug function.

(defn debug [x](prn x) x)

(->> foo
    (debug)
    (bar))

👍 3
roelof15:01:23

Why is the healing-potion not updated right

(def warrior (ref {:hitpoint 15}))

(def healer (ref {:healing-potion 50}))


(defn heal [warrior healer]
   (dosync 
      (alter warrior update-in [:hitpoint] (partial + 25))
      (alter healer update-in [:healing-potion] (partial - 25))
  (get-in [:hitpoint] @warrior))
  (get-in [:healing-potion] @healer)
    (println warrior)
          (println healer))

(heal warrior healer)
outcome :
#ref[{:status :ready, :val {:hitpoint 40}} 0x14060ef1]
#ref[{:status :ready, :val {:healing-potion -25}} 0x2953a377]
nil

Stuart15:01:00

are you doing (- 25 50), so 25 - 50 = -25? when you want (- 50 25) 50-25 = 25?

Stuart15:01:16

so if you chang ethe (partial - 25) to (partial - 13) you will get result of -37

Stuart15:01:57

(partial - 25) is returning another function, which the 50 is passed to, so its doing (- 25 50), I think.

andy.fingerhut15:01:22

Instead of using partial, you might want something like (fn [cur] (- cur 25)), or an abbreviated form that Clojure allows for functions: #(- % 25)

👍 3
Stuart15:01:05

It doesnt matter for + as 5+6 = 6+5, but 5-6!=6-5

roelof15:01:12

@andy.fingerhut does not make a difference

roelof15:01:36

#ref[{:status :ready, :val {:hitpoint 40}} 0x278238d9]
#ref[{:status :ready, :val {:healing-potion -25}} 0x40bd1764]
nil
code :
(def warrior (ref {:hitpoint 15}))

(def healer (ref {:healing-potion 50}))


(defn heal [warrior healer]
  (dosync
   (alter warrior update-in [:hitpoint] (partial + 25))
   (alter healer update-in [:healing-potion] #(- % 25)))
  (get-in [:hitpoint] @warrior))
(get-in [:healing-potion] @healer)
(println @warrior)
(println @healer)

(heal warrior healer)

Stuart15:01:18

@andy.fingerhut solution works for me.

(defn heal [warrior healer]
  (dosync
    (alter warrior update-in [:hitpoint] (partial + 25))
    (alter healer update-in [:healing-potion] #(- % 25))
    (get-in [:hitpoint] @warrior))
  (get-in [:healing-potion] @healer)
  (println warrior)
  (println healer))

=> #'stuartstein777.aoc/heal
(def warrior (ref {:hitpoint 15}))

=> #'stuartstein777.aoc/warrior
(def healer (ref {:healing-potion 50}))

=> #'stuartstein777.aoc/healer
(heal warrior healer)

#object[clojure.lang.Ref 0xce48ab9 {:status :ready, :val {:hitpoint 40}}]
#object[clojure.lang.Ref 0x641e467b {:status :ready, :val {:healing-potion 25}}]

Stuart15:01:30

Did you resend the function to the repl after changing it?

roelof15:01:29

maybe a parentheses wrong

roelof15:01:33

Now it works

roelof15:01:50

second question

roelof15:01:14

how I can I now print the warrior and the healer instead of refs

andy.fingerhut15:01:19

For most kind of "mutable containers" in Clojure, including refs, atoms, and agents, you can use (deref x) to get the value "inside".

Stuart15:01:23

deref it? (println (deref warrior))

andy.fingerhut15:01:31

The syntax @x is a shorthand for (deref x)

roelof15:01:15

yep, found that out

roelof15:01:46

last part of the puzzle . healing points cannot be more then 40

roelof15:01:56

and the potion cannot be less then zero

andy.fingerhut15:01:33

Inside of the dosync, you can have conditional code like if or cond that checks whatever conditions you want, before it makes any calls to alter

roelof15:01:40

maybe use let-if ??

Stuart15:01:18

do you mean that even though healing potion is 50, you only want to use 40 of those points?

andy.fingerhut15:01:36

Minor comment: In your code pasted above, the expression (get-in [:hitpoint] @warrior) does get the new value from the warrior ref, and I am pretty sure that value is returned from the dosync expression, but there is nothing that can ever "see" or receive that return value, so it is redundant and unnecessary. The same applies to the following expression (get-in [:healing-potion] @healer)

andy.fingerhut15:01:51

The code will do the same thing, slightly faster, if those two expressions are removed from the function heal

andy.fingerhut15:01:57

I mention it not so much because of the performance issue, but for learning purposes it is good to know that such expressions are almost always useless - they are pure functions of their input with no side effects, and their return value is ignored.

dpsutton15:01:30

also, the arguments appear to be backwards

andy.fingerhut15:01:34

Doh! I should have noticed that, too. I guess it is a good thing those expressions are redundant, then 🙂

roelof15:01:14

hmm, why here a nullpointer exception

(defn hitpoint-validator[{:keys [hitpoint]}]
  (and (<= hitpoint 40)))

(defn potion-validator [{:keys [potion]}]
  (and (>= potion 0)))

(def warrior (ref {:hitpoint 15}
                  :validator hitpoint-validator))

(def healer (ref {:healing-potion 50}
                 :validator potion-validator))

samoleary15:01:23

You're destructuring a different key in potion-validator to what you have in healer, :healing-potion vs potion

roelof16:01:04

thanks, that was it

roelof15:01:33

I get that when ttrying the healer

dpsutton15:01:21

potion versus healing-potion

roelof15:01:33

thanks, it works

roelof16:01:04

the only thing I do not like is that it chrashes on a illigal state

roelof16:01:03

(defn hitpoint-validator [{:keys [hitpoint]}]
  (<= hitpoint 40))

(defn potion-validator [{:keys [healing-potion]}]
  (>= healing-potion 0))

(def warrior (ref {:hitpoint 15}
                  :validator hitpoint-validator))

(def healer (ref {:healing-potion 50}
                 :validator potion-validator))


(defn heal [warrior healer]
  (dosync
   (alter warrior update-in [:hitpoint] (partial + 25))
   (alter healer update-in [:healing-potion] #(- % 25)))
  (get-in [:hitpoint] @warrior))
(get-in [:healing-potion] @healer)
(println "warrior:" @warrior)
(println "healer: " @healer)

(heal warrior healer)

Antonio Bibiano17:01:21

I'm trying to parse a json using clojure.data.json but it wasn't in my project dependencies when I started the repl

Antonio Bibiano17:01:33

there is no way to include it on the fly?

Antonio Bibiano17:01:01

i'm currently using leiningen and calva

roelof17:01:45

I thought you can do this : `

(require '[clojure.data.json :as json])
@antbbn

roelof17:01:00

in the repl

popeye17:01:38

I would like to understand destructing in clojure, Anyone bookmarked helpful website?

popeye17:01:10

Thanks 🙂

dpsutton17:01:41

you need to restart the repl after adding it to your project dependencies

dpsutton17:01:00

(there are ways to accomplish this but they depend on tooling and are beyond the scope of #beginners imo)

Antonio Bibiano18:01:15

i still get this

Antonio Bibiano18:01:21

=> clojure.data.json
Syntax error (ClassNotFoundException) compiling at (form-init18181492875778679100.clj:1:1629).
clojure.data.json

Antonio Bibiano18:01:08

i put these in my :dependencies

Antonio Bibiano18:01:13

:dependencies [[org.clojure/clojure "1.10.0"]
                 [org.clojure/data.json "1.0.0"]]

hiredman18:01:16

clojure.data.json is the name of a namespace, it is not a name bound to a value, so it has no value evaluated at the repl

Antonio Bibiano18:01:00

you're right, i also tired this

=> (clojure.data.json/read-str "{}")
Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:471).
clojure.data.json

hiredman18:01:22

did you try the first example code block in the usage section?

Antonio Bibiano18:01:29

oh yeah :man-facepalming: i did not require it

Antonio Bibiano18:01:44

thanks for insisting 😄

roelof18:01:23

(ns brave-book.chapter11
  (:require [clojure.core.async
             :as a
             :refer [>! <! >!! <!! go chan buffer close! thread
                     alts! alts!! timeout]]))
error:
:as - failed: #{:only} at: [:only :op :quoted-spec :spec]
:as - failed: #{:rename} at: [:rename :op :quoted-spec :spec]
(quote :as) - failed: #{:exclude} at: [:exclude :op :spec]
(quote :as) - failed: #{:only} at: [:only :op :spec]
(quote :as) - failed: #{:rename} at: [:rename :op :spec]

dpsutton18:01:53

works for me

/tmp ❯❯❯ clj -A:async
Clojure 1.10.1
(ns brave-book.chapter11
  (:require [clojure.core.async
             :as a
             :refer [>! <! >!! <!! go chan buffer close! thread
                     alts! alts!! timeout]]))
nil
brave-book.chapter11=>

roelof18:01:40

very wierd

roelof18:01:55

with a ;lein project I do not seem to work

roelof18:01:21

or there is somewhere else a problem

(ns brave-book.chapter11
  (:require [clojure.core.async
             :as a
             :refer [>! <! >!! <!! go chan buffer close! thread
                     alts! alts!! timeout]]))

(defn hot-dog-machine
  []
  (let [in (chan)
        out (chan)]
    (go (<! in)
        (>! out "hot dog"))
    [in out]))

(let [[in out] (hot-dog-machine)]
  (>!! in "pocket lint")
  (<!! out))

roelof18:01:15

nope, only with the ns I see that problem

hiredman18:01:44

you should check the version of core.async you are using

dpsutton18:01:58

/t/foobar ❯❯❯ lein repl
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
nREPL server started on port 51406 on host 127.0.0.1 - 
REPL-y 0.4.4, nREPL 0.7.0
Clojure 1.10.1
OpenJDK 64-Bit Server VM 13.0.2+8
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

foobar.core=> (ns brave-book.chapter11
         #_=>   (:require [clojure.core.async
         #_=>              :as a
         #_=>              :refer [>! <! >!! <!! go chan buffer close! thread
         #_=>                      alts! alts!! timeout]]))
nil
brave-book.chapter11=>

hiredman18:01:07

and you haven't reported the full error

dpsutton18:01:11

i suspect the file isn't saved and you are evaluating something else

hiredman18:01:13

just part of the spec failure

roelof18:01:55

I have save it and the brave book uses these versions :

:dependencies [[org.clojure/clojure "1.10.0"]
                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]]

roelof18:01:26

oke, with a newer version it seems to work

hiredman18:01:44

newer versions of clojure are stricter about what they accept in ns forms, and some older versions of core.async have wonky ns forms

hiredman18:01:42

the full error instead of just the excerpt would have had some indication of which ns form was causing the problem, which likely would have shown it to be something in the core.async library, not in your code

roelof18:01:56

oke, I thought I had paste the full error

Ovidiu Stoica19:01:33

Hello, I am doing the Learn Reitit Course and working with next.jdbc , after connecting my DB with heroku, when I am trying to run my first sql command I get this error

Ovidiu Stoica19:01:02

The jdbc/execute part

Ovidiu Stoica19:01:50

Here is the user.clj file, I will provide more if needed

(ns user
  (:require [integrant.repl :as ig-repl]
            [integrant.core :as ig]
            [integrant.repl.state :as state]
            [cheffy.server]
            [next.jdbc :as jdbc]))

(ig-repl/set-prep!
  (fn [] (-> "resources/config.edn" slurp ig/read-string)))

(def go ig-repl/go)
(def halt ig-repl/halt)
(def reset ig-repl/reset)
(def reset-all ig-repl/reset-all)

(def app (-> state/system :cheffy/app))
(def db (-> state/system :db/postgres))

(comment
  (app {:request-method :get
        :uri            "/swagger.json"})
  (jdbc/execute! db ["SELECT * FROM recipe"])
  (go)
  (halt)
  (reset))

Ovidiu Stoica19:01:55

Nevermind, I fixed it. But Don’t ask me how xD

seancorfield19:01:21

@ovidiu.stoica1094 Looks like you may have evaluated that code before db was initialized.

roelof20:01:00

is there a way I do not have to explicit return nil :

(defn distance [strand1 strand2] 
  (if (= (count strand1) (count strand2))
    (->>  (map vector strand1 strand2)
          (map (partial reduce not=))
          (filter true?)
          (count))
    nil))

Henri Schmidt20:01:45

@roelof simply remove the else clause

Henri Schmidt20:01:10

by default (if p x) returns nill if p is not satisfied

hiredman20:01:41

Or use when

roelof20:01:51

oke, but then I see a message that the else is missing

roelof20:01:07

@hiredman that seems to work Thanks

hiredman20:01:32

That message isn't from clojure, that message is from some extra tool you are using

👍 3
hiredman20:01:44

A linter or something

Henri Schmidt20:01:21

I'd prefer if over when in this case because you aren't performing sequential logic and don't need to evaluate the body in an implicit do block.

hiredman20:01:07

if vs. when was the one topic that caused the last dev team I was on to errupt into flames

bronsa20:01:52

odd hill to die on

seancorfield20:01:20

I seem to recall technomancy being a very fierce advocate of if instead of when?

clyfe21:01:19

I find `when` is a good signal for "else path returns nil" so that's what I use it for. Reads better. With `if` you have to squint to see there's no `else` part, particularly when there's more lines of code.

15
didibus21:01:59

I'll bite! I feel like you can't enforce semantics through conventions. So having when only for side effect is a "good intention", but in practice, it's not an enforceable semantic. So realistically you can't rely on it to guarantee you anything. Thus it seems futile to assume when is only for side effect, and a lost cause to nag everyone who "mistakenly" uses when for returning a useful nil instead of only for side effects.

didibus21:01:02

That means, even before debating the "usefulness and merits" of a construct that would "execute a side-effect if condition is true", I can assert that trying to make when behave with those semantics by pure convention is an exercise in futility.

seancorfield21:01:21

I always wondered what he would think about situations where you have "if some-condition then execute-side-effects else execute-other-side-effects"? Would he insist on "when some-condition execute-side-effects; when not some-condition execute-other-side-effects"?

😀 3
didibus21:01:13

when just isn't that construct, when returns the last result of expressions if cond, else nil. That's what it is, seems hopeless to pretend its something else by using it exclusively for a subset of what it can be used for. And I can see people trying to do that actually getting burned out trying, cause "Good Intentions" don't work to enforce things. They can reduce the occurrence of it, but never prevent it. So if you're not okay with anything but a full guarantee, you got to find a different approach. For example, you could make a new construct that always returns nil, but if cond it also runs some side-effect. Such a construct could only be used for side-effect (or as a sub for nil I guess). If you even wanted to prevent someone using it as a sub for nil, you could have it return an exception maybe, or a thing that when deref throws an execption: Not allowed to use return of ...., ..... is only to be used for side-effects. Something like that.

seancorfield21:01:55

(although maybe he's really only railing against (when some-condition some-return-value) and preferring (if some-condition some-return-value nil) except with an implicit nil? I find it a hard position to justify)

didibus21:01:11

That's what I thought the idea was. I'm not sure if its when only for side effect, and if only for pure logic, or only the former.

didibus22:01:16

I think the idea was that at a glance, if you see when, you know some side effect is happening in that piece of code. (and if you use when for pure behavior, that messes up with this "at a glance" reading)

didibus22:01:58

So in order to be able to trust your "at a glance" reading of the code, you need people to only use when for side effects. Which, like I said, I think is an exercise in futility 😛

didibus22:01:34

(defmacro maybe-do
  [condition & forms]
  `(do (when ~condition ~@forms)
     (delay (throw (ex-info "Can't read from void return!" {:type :void-return-error})))))
Something like this would be better. Now I don't know if I'm convinced in how useful it is to use this to indicate "hey I'm doing side effect here, nothing else!!", but at least you can be sure that when someone uses that, its only doing side effect.

Henri Schmidt20:01:53

@hiredman what was the conclusion?

hiredman20:01:06

There are takes on this topic, and debates that go back to common lisp

hiredman20:01:22

There was no conclusion, only conflict

😂 3
Henri Schmidt20:01:40

Interesting, I have never heard of this debate before...

andy.fingerhut20:01:01

I think it is interesting to hear the debate at most once 🙂

Henri Schmidt20:01:28

Is the debate on the other side an argument that the implicit do block avoids accidental else clauses?

dpsutton20:01:10

the version i've heard is that when is only for side effects. and otherwise use if even if it only has a single branch. I don't understand the logic of it

andy.fingerhut20:01:30

I believe one side of the debate argues that when does (or should) imply that the expression is there for side effects, but if does not imply that.

Henri Schmidt20:01:44

That seems to be my reasoning as welll...

andy.fingerhut20:01:30

Nothing in the language behavior itself requires or implies either side of the debate, that I know of. It is a matter of style that some developers feel very strongly about. Not miles away from a tabs vs. spaces debate.

hiredman20:01:10

But by that logic, fn forms should only be used for side effects, and cond forms should never have side effects

hiredman20:01:27

The when implies side effects camp originates, I believe in common lisp, where an influential comp.lang.lisp poster took that position a long time ago

bronsa20:01:32

to end this debate once and for all we should just have a when! macro for side-effects

😛 3
hiredman20:01:09

I am trying to remember the guys name to see if I can dig up the post

dpsutton20:01:12

but it will have a 1/1000 chance of not executing body even when the test is true

bronsa20:01:48

that'd be when?!?

bronsa20:01:16

within the macro, you can suffix every symbol with ! to signal side-effects and it will automatically work

hiredman20:01:29

I think his last name started with an N

bronsa20:01:38

erik naggum?

hiredman20:01:02

That must be it

andy.fingerhut20:01:36

No, no. Don't end the debate. Simply try to find a way that it wastes more times for your competitors/opponents than it does for you 🙂

hiredman20:01:00

technomancy was a member of the team I mentioned

seancorfield20:01:42

I seem to recall quite a heated discussion on IRC around that time (2012) 🙂

didibus21:01:55

To me "when" for side effect ONLY seem to not make any sense in a language that doesn't have void returns

clyfe21:01:19

I find `when` is a good signal for "else path returns nil" so that's what I use it for. Reads better. With `if` you have to squint to see there's no `else` part, particularly when there's more lines of code.

15
hiredman21:01:44

I think rich at some point posted something to the Google group saying when is idiomatic for single branch conditionals, but some felt he was wrong or that his wording was ambiguous in someway (could have been, I don't really recall)

hiredman21:01:04

An annoying this is googling if and when is basically impossible

roelof21:01:35

oops, sorry for my question

andy.fingerhut21:01:07

The debate was there before your question, and will remain after your question 🙂

roelof21:01:03

o, I thought this discussion was about if versus when and I started a question how to do things better without explicit return nil

andy.fingerhut21:01:01

The debate is over 20 years old, I think.

andy.fingerhut21:01:14

starting before Clojure existed.

😁 3
roelof21:01:23

looks I started it again with my question

andy.fingerhut21:01:34

This is a mild reasonable one, though 🙂

Alex Miller (Clojure team)21:01:20

I don't remember if Rich has said that or not, but I've said it and that's my opinion

seancorfield22:01:38

Just so I'm clear on what "it" you're referring to, are you advocating:

(defn foo [x]
  (if (even? x)
    42))
over
(defn foo [x]
  (when (even? x)
    42))

didibus22:01:25

Hiredman said that he thought Rick said: > when is idiomatic for single branch conditionals So I assume this is what Alex is referring too. So it be that when your condition has a single branch, use when, otherwise use if or cond.

seancorfield22:01:54

Ah, that "it", not the other "it" 🙂

seancorfield22:01:36

(just that a lot of the earlier discussion focused on Phil Hagelberg's position which is the opposite of that)

Alex Miller (Clojure team)22:01:07

correct - when for single branch conditionals is my preference

seancorfield22:01:52

Thank you! I checked the (community) Clojure Style Guide and it doesn't seem to have an opinion on this particular issue. Which surprised me a bit.

caumond21:01:06

Not sure to follow you guys. At the end both forms are executing properly ? So its only a style issue. Am I right ? The 1/ 1000 sentence of @dpsutton and other comments make me doubting

hiredman21:01:45

yes, it is a style issue

dpsutton21:01:05

sorry. the 1/1000 randomness was just a joke 🙂

caumond21:01:16

No pb, my not so good english and clojure doubts are sometime an awful mix

dpsutton21:01:06

well i'm glad you asked. doubt anyone ever minds being asked for clarification.

seancorfield22:01:38

Just so I'm clear on what "it" you're referring to, are you advocating:

(defn foo [x]
  (if (even? x)
    42))
over
(defn foo [x]
  (when (even? x)
    42))

didibus22:01:49

I think the more common use in Clojure is: * When you have 1 branch use when * When you have 2 branch use if * When you have 3 or more branch use cond * When you want to choose between "one of many value" use case * If you need to do more than one thing per branch wrap it in a do unless you're using when, then you don't have to cause when is unambiguous so do would be redundant. * Side effect or not, it doesn't matter

18
🙌 3