Fork me on GitHub
#beginners
<
2020-08-24
>
fredmonroe02:08:09

what's a preferred library method for formatting long floating point numbers and or currency strings? i'm seeing a lot of choices and am wondering if there is something most people choose?

alexmiller02:08:24

the JDK has an extensive library built into it for both of these

alexmiller02:08:52

java.text.NumberFormat/java.text.DecimalFormat are good classes to look at - both of these have support for locale-specific formatters and custom stuff

chucklehead03:08:37

I'm working with XML and was considering using multimethods with dispatch based on tag name. I have several tags/types that share the same schema but have different names in various messages. Would something like this be the right way to create a common handler for those tags? 

(derive :ns/a :common/thing)
(derive :ns/b :common/thing)

(defmulti parse-element :tag)
(defmethod parse-element :common/thing
  [element]

  ...)

hiredman05:08:15

I would pull the body implementation of parse-element as a defn for any shared implementations and have the defmultis call that before using derive

Schpaa07:08:29

Is there a shortcut to make a map out of some identifiers/values; say: this that those -> {:this this :that that :those those} ?

kwrooijen07:08:14

This is one way, maybe someone has a simpler version:

(into {} (mapv (juxt keyword identity) ['this 'that 'those]))

Schpaa07:08:42

I like that one

Lu07:08:31

Mmm zipmap?

gon07:08:35

(defmacro gkzipmap [& args] (zipmap (map keyword '[email protected]) [email protected]))``

😀 1
Endre Bakken Stovner10:08:09

I have this piece of code in a go-block:

(if (< val (@store :last-found))
  ;cleanup like close channel and such
)
Is there a way to ensure only one thread enters that if?

Ben Sless11:08:44

You can create an atom which every task increments when it starts and decrements it after it finishes. Only enter the cleanup piece of code if the atom is zero. Another option is, if you run all your tasks in go blocks or threads, is use the facts they return channels, then write code which waits for takes from all tasks to complete (meaning they're done). Then wait for that code to complete. You're guaranteed to have it complete only after all tasks have finished.

👍 1
Ben Sless11:08:13

Toy example:

(require '[clojure.core.async :as a :refer [go chan <! <!! >! >!! thread]])

(defn task [args]
  (Thread/sleep 500)
  (println args)
  args)

(defn drain
  [ch]
  (go
    (loop []
      (when-let [x (<! ch)]
        (recur)))))

(time (<!! (drain (a/merge (map (fn [x] (go (task x))) (range 32))))))

Ben Sless11:08:44

Note that the go-blocks thread pool has only 8 threads by default, so the above code will take ~2seconds to run

👍 1
Trung Dinh13:08:54

hi again, a question about error handling please, how do you do it when doing filter? e.g I have 2 vectors and want to filter one based on elements of the other like this:

(def tmsall [{:givenName nil :surname nil :email "[email protected]"}
             {:givenName "Alice" :surname "Spring" :email ""}
             {:givenName "Bob" :surname "Summer" :email "[email protected]"}
             {:givenName "Carol" :surname "Autumn" :email "[email protected]"}
             {:givenName nil :surname nil :email "[email protected]"}
             {:givenName "Danny" :surname "Winter" :email "[email protected]"}
             ])

(def tslack ["Bob Best Summer" "Alice Spring"])

(try (filter (fn [m] (some (fn [s]( and (clojure.string/includes? s (:givenName m))
                                   (clojure.string/includes? s (:surname m)))) tslack))
             tmsall)
     (catch Exception e (str "exception: " (.getMessage e))))
the clojure.string/include? will throw java.lang.NullPointerException , I tried the try…catch above but not seems to work. And second question, if I just want to skip such Exception and run the filter with the rest of the elements, is it possible to do that? Thanks

alexmiller13:08:51

filter returns a lazy seq so it won't throw until that is later realized

alexmiller13:08:24

you probably want to move the try/catch into the fn (or better, test for nil)

dpsutton13:08:24

and you could easily add another filter to just ones with both a :givenName and a :surname

Trung Dinh13:08:08

I guess that’s why people never use try…catch with lazy seq return functions, that makes sense…, I just try putting the try/catch in the fn, and yes it catch the exception, interestingly, those nil elements also added to the final filtered elements… @dpsutton I was trying to use includes? as some of them have middle name/strange other name formats 🙂 … anyway, thanks @alexmiller, @dpsutton

Zebra15:08:27

How to refer to dev ns in comment blocks? for example when using component

(comment 
  (fn-call dev/system additional arg))

mloughlin16:08:50

is the dev namespace loaded into REPL?

mloughlin10:08:45

if the dev namespace has been loaded into the REPL (and has the system var at the time of evaluation) I think dev/system should be accessible. Maybe someone else knows otherwise?

mloughlin10:08:17

in my current REPL I created a namespace called dev with (def system "hi") , then from a separate namespace eval'd

(comment 
  (prn dev/system))) => "hi"
and it works

Zebra10:08:56

then im probably doing it wrong? any tips on how to reexport required defn?

Zebra10:08:01

i use this from reloaded template

(ns dev
  "Tools for interactive development with the REPL. This file should
  not be included in a production build of the application.
  Call `(reset)` to reload modified code and (re)start the system.
  The system under development is `system`, referred from
  `com.stuartsierra.component.repl/system`.
  See also "
  (:require
   [ :as io]
   [clojure.java.javadoc :refer [javadoc]]
   [clojure.pprint :refer [pprint]]
   [clojure.reflect :refer [reflect]]
   [clojure.repl :refer [apropos dir doc find-doc pst source]]
   [clojure.set :as set]
   [clojure.string :as string]
   [clojure.test :as test]
   [clojure.tools.namespace.repl :refer [refresh refresh-all clear]]
   [com.stuartsierra.component :as component]
   [com.stuartsierra.component.repl :refer [reset set-init start stop system]]
   [{{main-ns}}]))

;; Do not try to load source code from 'resources' directory
(clojure.tools.namespace.repl/set-refresh-dirs "dev" "src" "test")

(defn dev-system
  "Constructs a system map suitable for interactive development."
  []
  (component/system-map
   ;; TODO
   ))

(set-init (fn [_] (dev-system)))
i can refer to dev/system in repl prompt but not in comment blocks

mloughlin10:08:43

how are you evaluating the comment expression?

Zebra10:08:10

cursive evaluate

mloughlin10:08:38

I don't know Cursive, but with my editor that type of evaluation just sends the s-expression to the REPL like a copy/paste almost. What happens if you run require from your comment before trying to eval the system variable? (comment (require 'dev) (dev/system ...))

mloughlin10:08:46

(also, what error message do you get?)

Zebra10:08:58

it works

1
stopa19:08:23

Hey team, noob question -- how would you debug this? Context: I am trying to upload a file to google cloud. I look at https://googleapis.dev/java/google-cloud-storage/latest/com/google/cloud/storage/Bucket.html#create-java.lang.String-java.io.InputStream-com.google.cloud.storage.Bucket.BlobWriteOption...- And try to replicate it:

(def bucket (-> (StorageClient/getInstance) .bucket)
;; #object[com.google.cloud.storage.Bucket 0x4f155e75 "Bucket{name=journaltogether.appspot.com}"] 

(def input-stream (FileInputStream. (:tempfile file)))
;; #object[java.io.FileInputStream 0x59d8712 "[email protected]"]
And now I try:
(.create bucket "foooo.png" input-stream "image/png" (into-array Storage$BlobWriteOption []))
This tells me:
No matching method create found taking 4 args for class com.google.cloud.storage.Bucket
Buut, it does seem to have these: -- How could I debug further?

dpsutton19:08:33

Clojure is dynamic and doesn’t have the type information. There are four overloads for this method but clojure needs to figure out which of those four to invoke. If you type hint your args you can give clojure more information so that it can choose which of the four to call.

❤️ 1
seancorfield19:08:06

You might be able to get away with just hinting ^.InputStream input-stream ^String "image/png" but you might also need to hint the fourth argument which is a bit trickier/less obvious.

❤️ 1
stopa19:08:57

Okay getting close!

stopa19:08:26

(defn upload-att [{:keys [filename ^String content-type tempfile] :as att}]
  (let [bucket (.bucket (StorageClient/getInstance))
        ^String blob-name (str (UUID/randomUUID)
                               "/"
                               filename)
        ^InputStream input-stream (FileInputStream. tempfile)
        ^Storage$BlobWriteOption options  (into-array Storage$BlobWriteOption [])]
    (.create
      bucket
      blob-name
      input-stream
      content-type
      options)))
I typed all of these guys, but it still seems to be having trouble. My intuition is that I typed something incorrectly. maybe options?

stopa19:08:18

Aha!

(defn upload-att [{:keys [filename content-type tempfile] :as att}]
  (let [bucket (.bucket (StorageClient/getInstance))
        blob-name (str (UUID/randomUUID)
                               "/"
                               filename)
        input-stream (FileInputStream. tempfile)
        options (into-array Bucket$BlobWriteOption [])]
    (.create
      bucket
      ^String blob-name
      ^InputStream input-stream
      ^String content-type
      options)))
Did the trick. Thanks for the help team!