Fork me on GitHub
#beginners
<
2021-05-16
>
evocatus00:05:48

I noticed that Clojure has a BIG incentive to write small functions - you cannot write long imperative walls of text here because every new binding (`let`, loop, etc.) increases nesting level

simongray08:05:42

Some people get around that by writing all of their imperative code inside the let binding vector 😉

☝️ 4
teodorlu13:05:51

You'll find some examples of "big let" in #babashka source

teodorlu13:05:00

(let [x 3
      ;; _ -> discard return
      _ (spit "file" x)]
  (* x 10))

teodorlu13:05:00

Clojure core functions are often quite big

Ivan Koz08:05:11

@vale isn't that a perfect case for a macro?

valerauko09:05:54

i've tried. with-meta won't tag array types for me...

(defmacro ->typed-array
  [klass things]
  `(with-meta
    (into-array ~klass ~things)
    {:tag (str "[L" ~(.getName klass) ";")}))
(->typed-array Map []
ClassCastException class [Ljava.util.Map; cannot be cast to class clojure.lang.IObj ([Ljava.util.Map; is in module java.base of loader 'bootstrap'; clojure.lang.IObj is in unnamed module of loader 'app')

valerauko09:05:54

i've tried. with-meta won't tag array types for me...

(defmacro ->typed-array
  [klass things]
  `(with-meta
    (into-array ~klass ~things)
    {:tag (str "[L" ~(.getName klass) ";")}))
(->typed-array Map []
ClassCastException class [Ljava.util.Map; cannot be cast to class clojure.lang.IObj ([Ljava.util.Map; is in module java.base of loader 'bootstrap'; clojure.lang.IObj is in unnamed module of loader 'app')

Alex Miller (Clojure team)13:05:01

arrays, as Java objects, have no place to put meta

valerauko13:05:57

it's weird that the compiler knows it's a java object that can't take meta but still demands type hints for it

Alex Miller (Clojure team)13:05:28

you're confusing what's known at compile-time and run-time

Alex Miller (Clojure team)13:05:59

what you're really looking for is something that sets the return type on the into-array expression (the code, which is a list) such that the compiler can resolve the surrounding Java interop call at compile time into a non-reflective call

valerauko13:05:00

thanks that was a gloriously nice hint

valerauko13:05:04

i got it working

valerauko13:05:11

(defmacro ->typed-array
  [klass things]
  (let [^Class resolved (resolve klass)]
    (with-meta
     (list 'into-array resolved things)
     {:tag (str "[L" (.getName resolved) ";")})))

Alex Miller (Clojure team)13:05:20

was just going to post that :)

valerauko13:05:35

it would be smooth sailing if this was into-array's built-in behavior

valerauko13:05:38

with this i could get rid of all the into-array type hint monsters

Alex Miller (Clojure team)13:05:53

well it wouldn't be a function then

Alex Miller (Clojure team)13:05:18

so that's not a thing we could change

Alex Miller (Clojure team)13:05:14

but could be a new wrapper macro

Ivan Koz14:05:50

@vale a little snippet how to get array classes programmatically

(let [classes  (apply list java.lang.String java.lang.Object (map (comp eval symbol second) primitives-classnames))]
  (map #(.. (do %) (arrayType) (getName)) classes))

=> ("[Ljava.lang.String;" "[Ljava.lang.Object;" "[F" "[I" "[J" "[Z" "[C" "[D" "[B" "[S")