clojurescript

carnundotcom 2025-08-26T16:57:49.702829Z

Huh? 😄

((fnil inc -1) :foo)    ; => ":foo1"
((fnil inc 0) :foo)     ; => ":foo1"
((fnil inc 666) :foo)   ; => ":foo1"
((fnil inc "bar") :foo) ; => ":foo1"

liebs 2025-08-27T07:01:53.395359Z

I think OCaml has the least annoying type system of any strongly and statically typed language I've ever used, but ymmv, or whatever

carnundotcom 2025-08-26T16:58:16.693419Z

1.11.132, by the way.

carnundotcom 2025-08-26T16:58:34.865469Z

Oh, and:

(inc :foo)              
; => ------ WARNING - :invalid-arithmetic ----------------------------------------------                                                                                                                                                 
;    Resource: <eval>:1:1                                                                                                                                                                                                                    
;    cljs.core/+, all arguments must be numbers, got [cljs.core/Keyword number] instead                                                                                                                                                      
;    -----------------------------------------------------------------------------------                                                                                                                                                         

dpsutton 2025-08-26T16:59:40.580439Z

this is just testing that (+ x) = x for all x i think nope

1
p-himik 2025-08-26T16:59:47.799459Z

That's expected due to how the underlying JS works. The warnings comes from the compiler when it has type info available. fnil erases type info.

❤️ 2
carnundotcom 2025-08-26T17:00:04.753599Z

Clojure (1.12.0) is more in line with expectations:

((fnil inc -1) :foo)
; => 
; Execution error (ClassCastException) at sx.clj.statistics.dbops/eval162409 (REPL:484).
; class clojure.lang.Keyword cannot be cast to class java.lang.Number (clojure.lang.Keyword is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

p-himik 2025-08-26T17:00:59.252109Z

Because Java is strongly typed and JavaScript is weakly typed. When trying to add something that's not a number to a number, both of the arguments get converted to a string and are the concatenated. Blame JS, not CLJS. :)

carnundotcom 2025-08-26T17:02:25.800109Z

> Blame JS, not CLJS Oh, happily! 😆

carnundotcom 2025-08-26T17:15:46.259539Z

Shame that these js* type hints get dropped by fnil...

(core/defmacro ^::ana/numeric +
  ([] 0)
  ([x] (core/list 'js* "(~{})" x))
  ([x y] (core/list 'js* "(~{} + ~{})" x y))
  ([x y & more] `(+ (+ ~x ~y) ~@more)))

; ...

(defn inc
  "Returns a number one greater than num."
  [x] (cljs.core/+ x 1))

; ...

(defn fnil
  "Takes a function f, and returns a function that calls f, replacing
  a nil first argument to f with the supplied value x. Higher arity
  versions can replace arguments in the second and third
  positions (y, z). Note that the function f can take any number of
  arguments, not just the one(s) being nil-patched."
  ([f x]
   (fn
     ([a] (f (if (nil? a) x a)))
     ([a b] (f (if (nil? a) x a) b))
     ([a b c] (f (if (nil? a) x a) b c))
     ([a b c & ds] (apply f (if (nil? a) x a) b c ds))))
  ([f x y]
   (fn
     ([a b] (f (if (nil? a) x a) (if (nil? b) y b)))
     ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) c))
     ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) c ds))))
  ([f x y z]
   (fn
     ([a b] (f (if (nil? a) x a) (if (nil? b) y b)))
     ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c)))
     ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c) ds)))))
I've thought about this for all of two seconds of course, but couldn't fnil be made to preserve them?

p-himik 2025-08-26T17:19:12.221889Z

I think they get dropped by every higher-order function. So in order to make it effective, you'd have to change everything. And then your own higher-order functions will be a problem. Or not even higher-order ones - a regular function that returns, say, a number, but does so in a way that escapes type inference, will be typed as basically any?. So in order to make it work across the whole or even most of the code, everybody would have to tag every function they write. Or the type inference machinery has to become so clever that it just knows everything, but I'm pretty sure it's not something anyone has figured out yet.

❤️ 2
🙏 2
carnundotcom 2025-08-26T17:22:08.384519Z

Hmm, right. I'd not want to open that can of worms either.

2025-08-26T17:40:42.692609Z

lol you've described Ocaml, which is both as cool and as annoying as you might imagine from that description

😁 1