clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
Adam Kalisz 2021-06-30T00:23:58.097900Z

Trying to use cljs.tools.reader.edn/read-string on "#uuid \"a8367bc1-690e-4a73-aecf-f2b9b3ff586e\"" but it fails with "No reader function for tag uuid." what am I doing wrong?

Adam Kalisz 2021-06-30T00:25:48.098100Z

ExceptionInfo repl-input.cljs [line 1, col 25] No reader function for tag reader/read-string. {:type :reader-exception, :ex-kind :reader-error, :file "repl-input.cljs", :line 1, :col 25} clojure.tools.reader.impl.errors/throw-ex (errors.clj:34) clojure.tools.reader.impl.errors/throw-ex (errors.clj:24) clojure.tools.reader.impl.errors/reader-error (errors.clj:40) clojure.tools.reader.impl.errors/reader-error (errors.clj:36) clojure.tools.reader.impl.errors/throw-unknown-reader-tag (errors.clj:206) clojure.tools.reader.impl.errors/throw-unknown-reader-tag (errors.clj:205) clojure.tools.reader/read-tagged (reader.clj:861) clojure.tools.reader/read-tagged (reader.clj:848) clojure.tools.reader/read-dispatch (reader.clj:73) clojure.tools.reader/read-dispatch (reader.clj:68) clojure.tools.reader/read*/fn--1314 (reader.clj:925) clojure.tools.reader.reader-types/log-source*/fn--962 (reader_types.clj:322)

Adam Kalisz 2021-06-30T00:34:05.098600Z

Oh, ok, it seems tagged literals are Clojure only...

thheller 2021-06-30T05:15:10.099700Z

@adam.kalisz tagged literals work find in CLJS too. but the stacktrace shows that you are using clojure.tools.reader? not cljs.tools.reader? how are you using it?

thheller 2021-06-30T05:16:07.100500Z

No reader function for tag reader/read-string looks like you are using #reader/read-string?

Simon 2021-06-30T14:25:48.103200Z

Can this ClojureScript snippet become more Idiomatic? I converted this JS snippet (https://www.movable-type.co.uk/scripts/latlong.html)

const R = 6371e3; // metres
const φ1 = lat1 * Math.PI/180; // φ, λ in radians
const φ2 = lat2 * Math.PI/180;
const Δφ = (lat2-lat1) * Math.PI/180;
const Δλ = (lon2-lon1) * Math.PI/180;

const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
          Math.cos(φ1) * Math.cos(φ2) *
          Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

const d = R * c; // in metres
to this CLJS
(defn gps-distance
  "calculates distance between gps coordinates in km
   from: {:lat :lon}
   to: {:lat :lon}
   "
  [from to]
  (let [R 6371 ;;km
        pi (.-PI js/Math)
        phi-1 (* (:lat from) (/ pi 180))
        phi-2 (* (:lat to) (/ pi 180))
        delta-phi (* (- (:lat to) (:lat from)) (/ pi 180))
        delta-lambda (* (- (:lon to) (:lon from)) (/ pi 180))
        a (+ (* (.sin js/Math (/ delta-phi 2))
                (.sin js/Math (/ delta-phi 2)))
             (* (* (.cos js/Math phi-1) (.cos js/Math phi-2))
                (* (.sin js/Math (/ delta-lambda 2)) (.sin js/Math (/ delta-lambda 2)))))
        c (* 2 (.atan2 js/Math (.sqrt js/Math a) (.sqrt js/Math (- 1 a))))
        d (* R c)]
    d))

jaju 2021-07-02T05:15:01.136200Z

Am not too hands-on with cljs of late, but I suppose #(.cos js/Math %) (and the likes) can simply be replaced with js/Math.cos - right?

💯 1
p-himik 2021-07-02T09:59:42.153600Z

Yep!

👍 1
p-himik 2021-06-30T15:15:47.104100Z

You can use map destructuring to turn (:lat from) into from-lat. You can extract (/ pi 180) because you use it four times. You can extract (* x x) into a separate square function or use js/Math.pow to avoid having to compute the same thing twice. You could extract common math functions into extra defs to make gps-distance more readable.

🙌 2
p-himik 2021-06-30T15:17:01.104400Z

And I think you should be able to use Greek characters in CLJS sources with no problems. Whether it's idiomatic or not - depends on the area, I'd say.

dgb23 2021-06-30T15:21:56.104600Z

I mean it is a 1:1 translation of the js code. Maybe the code is meant to be explicit? But I think what @p-himik suggested seems the right way in general.

nate sire 2021-06-30T15:30:46.104900Z

I really liked how you put the comment at the top explaining what the code does

🙌 1
nate sire 2021-06-30T15:31:10.105100Z

I am a fan of using comments to explain why functions are there

p-himik 2021-06-30T15:35:53.105300Z

Just in case - that's not a comment, that's a proper docstring. It's available in the var's metadata as well, i.e. as (:doc (meta #'gps-distance)).

👍 1
nate sire 2021-06-30T15:44:24.105800Z

is it good practice to use ( ( to square ints... versus expt from the math lib...

nate sire 2021-06-30T15:46:16.106500Z

:require [clojure.math.numeric-tower :as math

nate sire 2021-06-30T15:46:42.106700Z

because of 1 less dependency?

p-himik 2021-06-30T15:47:54.106900Z

Yes. It's better to use built-in functions (e.g. *) and platform functions (e.g. js/Math.pow) when they do exactly the same as some function from some third-party dependency.

nate sire 2021-06-30T15:50:52.107500Z

I like your idea of extracting some of it into functions... because you can help me remember some pieces of the equations... with a well named function

nate sire 2021-06-30T15:51:53.107700Z

e.g.. area versus circumference as a function name instead of pi r ^ 2... just as an example

jaihindhreddy 2021-06-30T16:09:12.108Z

Is using a top-level let like this, a reasonable way of defining one-off fns, assuming they aren't usable elsewhere in the namespace?

(let [R 6371 ;; km
      square #(* % %)
      PI (/ (.-PI js/Math) 180)
      cos #(.cos js/Math %)
      sin #(.sin js/Math %)
      atan2 #(.atan2 js/Math % %2)
      sqrt #(.sqrt js/Math %)]
  (defn gps-distance
    "calculates distance between gps coordinates in km"
    [{lat1 :lat lon1 :lon} {lat2 :lat lon2 :lon}]
    (let [φ1 (* lat1 PI)
          φ2 (* lat2 PI)
          Δφ (* (- lat1 lat1) PI)
          Δλ (* (- lon2 lon1) PI)
          a  (+ (square (sin (/ Δφ 2)))
                (* (cos φ1) (cos φ2))
                (square (sin (/ Δλ 2))))
          c  (* 2 (atan2 (sqrt a) (sqrt (- 1 a))))]
      (* R c))))
Also, will the tiny fns like the cos and sin be inlined by Google Closure in advanced mode? PS: Dunno if this is even allowed in CLJS. Haven't learned it yet.

p-himik 2021-06-30T16:11:17.108300Z

That's allowed. I can't answer the question about inlining, but I wouldn't worry about it. You have CLJS compiler running on top of GCC compiler, where the code ends up running on JS VM. You're so removed from the actual execution, that worrying about inlining such functions should be the last thing IMO.

👍 2
zendevil 2021-06-30T21:52:41.109900Z

I have an image tag that contains a url from the web:

[:img {:height 599
            :width 500
            :alt "Mike Wazowski"
            :src "<https://static.wikia.nocookie.net/sulleycinematicuniverse/images/0/0b/Greenbillycrystalwithoneeye.jpeg/revision/latest/top-crop/width/360/height/450?cb=20190614200344>"}]
However, upon loading this component, I’m getting a 404 in the console for this url, even though the image at the source exists.

p-himik 2021-06-30T21:54:58.110100Z

Sounds like it has nothing to do with #clojurescript and everything to do with how <http://static.wikia.nocokie.net|static.wikia.nocokie.net> processes requests. A server can choose to reply with any code, including 404, to any request.

dpsutton 2021-06-30T21:56:54.110300Z

agreed. this sounds like wikipedia saying they won't pay the hosting costs for images for your website

Cora (she/her) 2021-06-30T22:13:48.110500Z

do you think that setting referrerpolicy would give let you use it? https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-referrerpolicy

Cora (she/her) 2021-06-30T22:14:08.110800Z

I mean, absolutely host it yourself 😂 but if you're just playing around then maybe that'll let you get around it

olaf 2021-06-30T23:00:43.113800Z

What is the best way to catch a click outside a div (like a modal) in cljs+reagent? • .addEventListener that should be attached on componentDidMount and detached on unmount • a global overlay div attached to the bottom of the body

p-himik 2021-06-30T23:04:08.113900Z

If it's just handling of clicks and nothing else, then I don't think there's any functional difference. But if you want to apply some styles to the backdrop (e.g. opacity), then it needs to be a proper DOM node.

olaf 2021-06-30T23:15:23.114100Z

Okay thanks!