Fork me on GitHub
#beginners
<
2021-11-08
>
dabrazhe13:11:12

I would like to print the parameters based on the keyword selector

(defn shcomm [& comm printcommand]
 (when (= printcommand :print) (println (apply splitcomm comm)))  
  (apply sh (apply splitcomm comm)))

and use it like this: 

(shcomm "ls " "-a" :print)
The current version doesn't work, obviously, because the comm param. also incorporates :print. What's the right way to do this?

Bob B13:11:49

There are several ways to accomplish something like this. Generally, we want the "and then some number of things" arguments to be the last argument to use the & like that. However, if we're going to say "the last thing in that bunch of things is always special and separate", we could use a let block and bind (for example) printcommand to be (last comm) and then either use a different name or re-bind comm in the let scope as (butlast comm) . I think it might be more idiomatic, though, to take a list/vector as your comm value, so the call would end up looking something like (shcomm ["ls" "-a"] :print) . Alternatively, we could take printcommand as the first argument, and then the & comm bit would just work:tm: .

walterl16:11:47

I generally prefer an optional option map for these kind of... err... optional options:

(defn- shcomm
  [comm & [{:keys [print?]}]]
  (apply (if print? println sh) comm))

(shcomm ["ls" "-a"])
(shcomm ["ls" "-a"] {:print? true})

dabrazhe16:11:00

I guess I prefer butlast, was not sure if it's idiomatic, though. Wrapping param in vector makes if heavy and much less fun. So does the optional map

(shcomm "ls -la" :print) and (shcomm "ls -la") 

reads much less busy if you have dozens of these lines

walterl16:11:59

Command args in a vector communicates what's going on a lot clearer, though

dabrazhe17:11:41

What about functions like cheshire.core/parse-string, it uses the last true parameter to keywordise. How this kind of func are realised?

Fredrik17:11:39

cheshire.core/parse-string takes either one, two or three arguments. The first argument is always a single string.

Fredrik17:11:12

It looks like this

(defn parse-string
  ([string] (parse-string string nil nil))
  ([string key-fn] (parse-string string key-fn nil))
  ([^String string key-fn array-coerce-fn]
   (when string ... *THIS IS WHERE PARSING HAPPENS* ))))

dabrazhe14:11:57

well in my case I can't predict the arity, unless supplying the shell command as vector which is much less elegant imho

dabrazhe14:11:44

Actually, I can put the print param first.

(defn shcomm-print [printt & comm]
  (if (= :print printt) (do (println :comm comm)
                            (apply vector :result comm))
      (do
        (println :printt printt :comm comm)
        (apply vector :result printt comm))))

(= (shcomm-print  "a " "b " "c") (shcomm-print :print "a " "b " "c"))
But the same can be done with butlast as well.

Andy Carlile20:11:03

In F# there is a method for calling server functions from the client called https://github.com/Zaid-Ajaj/Fable.Remoting. Is there a similar strategy for accessing server data from the client? What's your favored strategy? (trying to stay full clj/cljs)

pithyless21:11:30

There are a couple RPC-style libraries floating around on GitHub, but not sure if they would be considered idiomatic. If you're looking for something bidirectional - perhaps something like https://github.com/ptaoussanis/sente is appropriate. But I find https://pathom3.wsscode.com/ to be a natural and idiomatic strategy for integrating client/server data.

JohnJ21:11:03

Why does using a transient here doesn't make any difference in performance? It's similar to this example https://clojure.org/reference/transients#_example

(defn unrolled-2 [v2]
  (loop [idx 0 agg (transient [])]
    (if (< idx (- (count v2) 7))
      (recur (inc idx)
             (if (> 1000 (- (nth v2 (+ idx 7)) (nth v2 idx)))
               (conj! agg idx)
               agg))
      (persistent! agg))))

JohnJ21:11:14

I'm passing this input FWIW (def times-v (into [] (take 1e6) (iterate #(+ % (rand-int 1000)) 0)))

hiredman21:11:00

maybe boxed math swamps the difference

alexmiller21:11:01

a) how big is v2 and how did you test? (the jvm often requires some warmup to see improvement) b) you may be dominated by the boxed math here rather than by the collection batching. many of the math ops here will end up being boxed math, which is ~100x slower than primitive math. count and nth will return boxed numbers here. if you use long to cast the result of count and (set! *unchecked-math* true) , that may help a bit

alexmiller21:11:42

agg is a coll, so the final objects are going to be boxed regardless

alexmiller21:11:25

you could also (set! *unchecked-math* :warn-on-boxed) to see additional warnings

alexmiller21:11:17

the second - is going to be boxed math as well as the nth results will be boxed

JohnJ22:11:14

thanks, is a example from a blog that I was trying to make fast without using arrays

alexmiller22:11:35

well, you're never going to approach arrays, where the numbers can stay primitive without being boxed

alexmiller22:11:32

you can use vector-of to store primitives, but the generic Clojure collection interfaces to get things in and out all require boxing and that's necessarily going to be a lot of overhead. transients helps a little, but I suspect the boxing/boxed math/unboxing costs are the worst of it.

alexmiller22:11:52

some day (maybe Java 18?) we'll get https://openjdk.java.net/jeps/401 and that will open some new options

alexmiller22:11:27

or I guess https://openjdk.java.net/jeps/402 is the part that will likely matter to us

alexmiller22:11:19

could potentially be a huge boost to Clojure default performance

JohnJ22:11:50

having connection issues... so that's something coming before valhalla?

JohnJ22:11:25

anyway, now I'm curious to create a Java version with arraylist to see the overhead of the persistent collection

alexmiller22:11:52

it's part of valhalla

alexmiller22:11:05

if I understand correctly

hiredman22:11:15

if it is the unchecked math stuff, then you won't be measuring the "overhead" of a persistent collection, you'll be measuring the speed of math with and without having to do dispatch to determine the types of the operands

hiredman22:11:59

the point is, when you call a function like nth it returns an Object so when you do math on it there is extra code to execute (type tests boxing/unboxing. etc)

Pablo23:11:16

Hello everyone Is there a way to get the full name of a namespace from its alias?

(ns app.foo.bar
  (:require [app.x.y.z :as z]))

(? 'z)
;; => app.x.y.z
(type (? 'z))
;; => clojure.lang.Symbol

Pablo23:11:34

I want to generate dynamically some names of specs to call them (s/valid? (? 'z (name key)) data)

Shawn00:11:03

(get (ns-aliases *ns*) 'z)

Shawn00:11:24

(ns user.foo
  (:require [clojure.string :as str]))

(get (ns-aliases *ns*) 'str)
;; => #namespace[clojure.string]