beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
practicalli-john 2020-11-10T02:02:11.447Z

seems like a #figwheel-main question. assuming its not covered in the docs https://figwheel.org/config-options.html#connect-url

Jim Newton 2020-11-10T11:02:27.448700Z

is there a way to have the reader insert the line number in what it read? E.g., (this is a line which contains .#(get-reader-line-number) the line number in it)

2020-11-10T13:27:04.449400Z

Why is `(seq x)` the idiomatic version of `(not (empty? x))`?

Ben Sless 2020-11-10T13:30:36.449500Z

I'm not sure this is a satisfactory explanation, but empty? is (not (seq ,,,)), so (not (not (seq ,,,))) isn't very idiomatic.

practicalli-john 2020-11-10T13:33:20.449700Z

You can see from the source code how empty? is actually implemented (not (seq coll)) https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core.clj#L6206 So as mentioned above, the not's really cancel themselves out...

2020-11-10T13:35:10.450100Z

Ah, that does make sense. Should the same be used for strings or is (not (clojure.string/blank? x)) appropriate? I suppose (complement clojure.string/blank?) is actually more idiomatic in that case..

Ben Sless 2020-11-10T13:37:35.450300Z

If I use it pervasively I define it as a function.

alexmiller 2020-11-10T13:38:33.450800Z

Not to my knowledge

2020-11-10T13:44:58.451Z

Since (coll? "x") is false, my understanding is that (seq "x") is not the appropriate way to check for a blank string and I should use clojure.string/blank? as I showed above. I get that if I use it often it should be defined as a fn in my code so as not to repeat it often.

practicalli-john 2020-11-10T14:10:59.451200Z

Regular expressions will give you a lot of expressiveness when checking strings and are often used with re-seq, re-find and re-matches There is a simple example here https://github.com/practicalli/exercism-clojure-guides/blob/master/bob/src/bob.clj This is a useful regex cheatsheet https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Cheatsheet

2020-11-10T14:14:08.451800Z

Thanks guys.

Steven Katz 2020-11-10T14:48:08.455100Z

I’ve written a little betting squares app as an exercise for learning Clojure. Is it appropriate to ask members of this channel to critique it? Looking for feedback on FP, idiomatic Clojure and code organization plus any other feedback. https://github.com/git4skatz/footballsquares

Darin Douglass 2020-11-10T15:09:50.455600Z

Small things I notice: 1. load is almost never what you want. instead do something like (:require [footballsquards.score :as score] ...) in your ns` form. 2. i'd personally recommend using vectors rather than lists where a you just need a generic sequential thing. 3. case rather than condp for compile-time-known values 4. -1 seems like a really odd exit code 5. use (ns footballsquares.*) instead of (in-ns '*) 6. the are cases where you use the generic symbol coll to indicate multiple "types" of things: players, squares, charities. use distinct, descriptive symbols to avoid confusion generally (aside from some other smaller whitespacing things that are more preference than anything), things looks pretty good to me! good job!

Jim Newton 2020-11-10T15:21:42.456300Z

I'm loving the https://github.com/brandonbloom/backtick. Bravo @bbloom... well done

Steven Katz 2020-11-10T15:25:41.456500Z

Thanks!!

Jim Newton 2020-11-10T15:35:55.457500Z

can someone help me understand why the nil? function uses (clojure.lang.Util/identical x nil) rather than (= x nil)

alexmiller 2020-11-10T15:40:32.458600Z

Speed

dpsutton 2020-11-10T15:40:48.458900Z

checking (source =) it would hit (clojure.lang.Util/equiv x y) and does a bunch of work depending on the type of x, when it just needs to compare identical x nil

Jim Newton 2020-11-10T15:41:30.459200Z

great so semantically it is the same?

Jim Newton 2020-11-10T15:41:51.459600Z

i.e., there are no values which are = to nil without being identical to nil?

2020-11-10T15:51:50.461200Z

I cannot think of any values x such that (= x nil) is true but (identical? x nil) is false. nil in Clojure is the reference null in the JVM, which I believe is effectively a null pointer.

2020-11-10T15:52:17.461600Z

That does not change the warning that identical?is rarely what you want to use in Clojure.

dpsutton 2020-11-10T15:54:57.461900Z

(= (reify Object (equals [x y] true)) nil) it seems you can get there but its your own shenanigans that do so

Jim Newton 2020-11-10T16:05:22.463500Z

does the clojure compiler have a clojure specific optimizer which for example sees an explicit call to (= nil x) and compiles it as (indential nil x) ?

dpsutton 2020-11-10T16:10:07.464300Z

do you suspect there is?

2020-11-10T16:30:35.464500Z

None that I am aware of.

alexmiller 2020-11-10T16:34:42.464900Z

There is no Clojure optimizer

alexmiller 2020-11-10T16:35:50.466500Z

The compiler mostly tries to make really obvious bytecode and then relies on hotspot to be an amazing dynamic optimizer with 100s of person years of work in it

phronmophobic 2020-11-10T18:33:46.467900Z

you can always try the #code-reviews channel for feedback too

Steven Katz 2020-11-10T18:58:08.468100Z

Thanks!

sergey.shvets 2020-11-10T19:50:36.470800Z

Hi, two noob questions on cljs.core.async. 1. Is it ok to read all available channel values inside the go-loop? I have a buffered channel where UI updates are posted and I would like to bulk it together. Code example:

(go-loop []
      (let [v        (async/<! b)
            all-vals (loop [vals [v]]
                       (let [next-v (async/poll! b)]
                         (if (some? next-v)
                           (recur (conj vals next-v))
                           vals)))]
        (js/console.log (str "Read " (count all-vals) " from channel") all-vals)
        (recur)))
1. It seems that I'm able to put 2 more messages than buffer size on a chan. Am I doing something wrong? thanks in advance!

chaow 2020-11-10T20:34:35.472800Z

quick question: is it possible to do a with-redefs but for an atom? On the clojure page it says that the change to the variable is visible in all threads. Id like a thread safe way of doing this

alexmiller 2020-11-10T20:41:25.473300Z

with-redefs is not thread-safe

alexmiller 2020-11-10T20:43:04.474600Z

unclear to mean if you are talking about a var referring to an atom or using an atom as an alternative to vars

chaow 2020-11-10T20:45:10.476300Z

Here is my problem: I have large code where I realize at the end of my logic we need to add a check that requires adding an argument in a whole chain of functions. I was thinking if it was possible to just have a global variable and then set that global variable in a thread safe manner as the value to be passed? But this doesnt sound right at all on second thought 😕

chaow 2020-11-10T20:45:21.476500Z

any solution to this?

chaow 2020-11-10T20:46:51.478100Z

say i have fn a, b, c, d. a calls b, b calls c, c calls d. I realize i need an argument on d, so i have to change all the callers of d, and all the callers of the callers of d etc. In my scenario, this branches out a lot, and it doesn't seem ideal to add an arg everywhere potentially hundreds of places.

alexmiller 2020-11-10T21:04:02.479900Z

@chaow one answer is to use a dynamic var and binding but using a dynamic var has all the downsides of global state so it's worth thinking very carefully about whether that's a worthwhile tradeoff

chaow 2020-11-10T21:07:06.480700Z

yes thats the issue, the code i need to run is parallel

chaow 2020-11-10T21:07:56.481800Z

so it seems like there's not a lot of other solutions, seems a bit against the DRY priniciple to have the args repeated everywhere only for one single use 😞

alexmiller 2020-11-10T21:14:32.482600Z

depending what you're doing, dynamic bindings work fine with some parallel constructs in clojure (many things like future will propagate dynamic bindings to threads)

phronmophobic 2020-11-10T21:15:23.483600Z

I’m pretty sure there are other options, but it’s difficult coming up with them based on the provided description

phronmophobic 2020-11-10T21:17:11.485100Z

if you have a chain of functions, it’s likely you can chain them without having them directly call each other.

seancorfield 2020-11-10T21:26:39.486800Z

@chaow If you're still at that point in evolving your design, perhaps consider passing a hash map down the call chain instead of individual arguments? That way only the top-level code has to change (to assoc in the new field that function d needs).

seancorfield 2020-11-10T21:28:42.488700Z

Also, REPL-driven development would tend to lead you to develop d first and you would probably have its arguments locked in before you write code that calls it. Not always true, of course, but working bottom-up via the REPL does help reduce this kind of refactoring churn in my experience.

➕ 2
chaow 2020-11-10T21:58:17.490400Z

the thing is im working in a company handling a lot of real time data so i really think dynamic vars aren't really safe to use. It was hard to do this at the design level because I wasn't there yet, im a fairly recent hire. I talked to my manager and we ended up dropping the feature because of how much code change we would need to do, guess this is a cost/benefit trade-off situation :man-shrugging:

2020-11-10T22:24:44.495400Z

I'm finding the error messages in Clojure pretty tough to track down what is actually wrong.

(ns clj-codewars.scratch2
  (:require [clojure.string :as str]
            [clojure.set :as set]))

(defn number->digits [num]
  (->> num str (map (comp read-string str))))

(defn disarium-number [number]
  (number->digits num) ; ***** error here, num should be number! *****
  )

(disarium-number 89)
When I try to send (disarium-number 89) to the REPL, the error I get is
Error printing return value at clojure.lang.Util/runtimeException
EOF while reading,
Not even any indication of where the error actually occured... Is their a package that can give me better help here for finding where the actual errors are in my code?

2020-11-10T22:25:14.495700Z

Is this something that clj-kondo would help with?

borkdude 2020-11-10T22:28:08.496500Z

@qmstuart your error is unfortunate, since num is a function in clojure core apparently

borkdude 2020-11-10T22:28:52.497300Z

so what happens is that in disarium-number you are not using your argument number, but you are passing the function clojure.core/num to number->digits

borkdude 2020-11-10T22:29:07.497700Z

clj-kondo will warn you about an unused argument in this case, so that could have been helpful

👍 1
dpsutton 2020-11-10T22:31:33.498500Z

i suspect there's some unbalanced parens going on based on the error being "EOF while reading". And at that point there's largely not much clojure can do to make the error message better

borkdude 2020-11-10T22:32:53.498900Z

@dpsutton the function clojure.core/num is stringified and then read as code.

dpsutton 2020-11-10T22:33:45.499400Z

ah i totally glossed over that read-string was involved. good catch

borkdude 2020-11-10T22:33:46.499500Z

user=> (map (comp read-string str) (str clojure.core/num))
Error printing return value at clojure.lang.Util/runtimeException (Util.java:221).
EOF while reading
(c l o j u r e . c o r e $ n u user=>

2020-11-10T22:47:17.001100Z

@qmstuart also, more generally, read-string is a powerful function (it can even cause arbitrary code to execute in some situations), and in your case Long/parseLong would be the safer (and weaker) option

2020-11-10T22:55:13.001300Z

oh, good to know! thanks!