Fork me on GitHub
#clojure
<
2018-05-10
>
seancorfield01:05:23

@kasuko Everyone hates Java logging...

☝️ 16
😝 8
tianshu03:05:26

I'm learning the clojure.core/seque function, and write the code like this:

(def reqs (range 10))

(defn p [s]
  (println (-> (Thread/currentThread)
                         .getName)
           s))

(defn send-reqs [reqs]
  (seque (map #(do (Thread/sleep 500)
                   (p "+")
                   (str %))
              reqs)))

(defn parse-resp [resp]
  (doseq [r resp]
    (do (Thread/sleep 500)
        (p "-")
        (str r "!"))))

(-> reqs
    send-reqs
    parse-resp)  ;; <-- execute this 
from the output, it's likely the parse-resp start after send-reqs finished, I suppose they will run together since in the doc of seque it says producer will run in background. what's going wrong with my code?

Dormo03:05:20

I noticed that Immutant is still using HornetQ, even though development ended on it long ago and it's been turned into ActiveMQ Artemis, which is actively maintained. Are there any plans to move it over? Alternatively, is there a reason it isn't necessary?

Dormo03:05:03

Hasn't been touched in awhile, but I imagine it still works

seancorfield04:05:21

@doglooksgood You're running into chunked sequences I suspect. Try it with a range bigger than 32 and you should see some interleaving.

tianshu05:05:32

@seancorfield yes, it's chunked. is there a simple way to dechunked. I found this:

(defn dechunk [s]
  (lazy-seq
   (when-let [[x] (seq s)]
     (cons x (dechunk (rest s))))))

seancorfield05:05:51

@doglooksgood Chunking doesn't normally matter at scale. If you need interleaving for small collections, you'll need to do that more explicitly.

tianshu05:05:32

so basically, I should build the lazy-seq with lazy-seq?

seancorfield05:05:03

Why does it matter?

seancorfield05:05:08

That's what I meant.

seancorfield05:05:40

Are you only working with small collections? Or are you planning to work with large collections too?

tianshu05:05:02

I want to send some request(about 100), and handle the resp one by one in another thread.

noisesmith18:05:21

lazy-seqs and side-effects are a poor mix, if knowing precisely when and how many results are realized is important for correctness, IMHO don't use laziness

seancorfield05:05:42

Perhaps core.async would be more suited?

danielneal08:05:27

I'm trying to get a regex to split a string on spaces, but include the space. I've got

(clojure.string/split "the cat sat on the (mat)" #"(?=\s)") ; => ["the" " cat" " sat" " on" " the" " (mat)"]
but really I want the space to sit at the end of each word rather than the beginning, like this:
["the " "cat " "sat " "on " "the " "(mat)"]
Is this a foolish thing to try and do with regexes?

andy.fingerhut09:05:45

I think regex's are certainly up to the task, but maybe the function split isn't a good fit.

andy.fingerhut09:05:40

What would you want to happen if there were initial spaces in the string to be split? Be in an initial string that contained only spaces?

danielneal09:05:43

ah good question about the initial spaces

danielneal09:05:55

I'll trim the string before hand

danielneal09:05:53

just for reference this is ui code I'm splitting the text so that I can do this:

andy.fingerhut09:05:53

Try this: (re-seq #"\S+\s*" "the quick brown fox")

danielneal09:05:12

aw neat! That looks great thank you!

danielneal09:05:33

I didn't think of re-seq

danielneal09:05:55

much better 🙂

andy.fingerhut09:05:08

Yeah, split is best when you are trying to remove some possibly repeated occurrences of a regex match, and return what did not match. re-seq is for returning repeated matches of your regex.

Bravi12:05:24

I’m trying to create a little command line application. I’m using app template and in my -main I’m just doing (println "Hello world") for now. whenever I create a standalone jar file using lein uberjar and when I try to execute it after doing chmod +x app.jar, it shows me the following error:

exec format error
I understand that this happens because the kernel doesn’t understand the language but how can I create an executable otherwise?

Alex Miller (Clojure team)12:05:14

The jar is your code, but it’s not executable without the jvm

Alex Miller (Clojure team)12:05:49

So here you code start it with java -jar app.jar

soulflyer12:05:45

@bravilogy This might be useful, it generates standalone apps: https://github.com/Raynes/lein-bin

joelsanchez12:05:28

now you can use Graal's native-image to create native executables too

ben.mumford15:05:27

hi all, i was wondering why the order of function arguments is what it is in clojure core. if i was writing a new function, what should i consider when determining the argument order? i asked a stackoverflow question here: https://stackoverflow.com/questions/50275513/rules-of-thumb-for-function-arguments-ordering-in-clojure

seancorfield15:05:38

@ben.mumford620 You mean the "sequences at the end, collections at the beginning" kind of thing?

seancorfield15:05:33

See, for example, Rich's comments in this thread https://groups.google.com/forum/#!topic/clojure/iyyNyWs53dc (from 2008)

ben.mumford15:05:38

yeah that kind of thing

ben.mumford15:05:18

some rules of thumb would be awesome, i'll check out the link. put the answer on the SO question and i'll give you some points (yum yum!)

sobel15:05:58

my thumb rule: i think about my options for creating partials of the function, as well as calling it in the context of a -> or ->> macro.

👍 4
lilactown17:05:56

I want to detect if a key in a map is accessed in a test I'm writing

lilactown17:05:19

in like a traditional OO lang I'd use a custom getter/trap/proxy/whatever

lilactown17:05:32

what's the best way to do that in Clojure?

ghadi17:05:14

that's an idiom more suited to a traditional OO lang

the2bears17:05:20

Maybe you could describe a bit more the intention of this test?

lilactown17:05:15

I'm testing a side-effectful operation that I'm mocking

lilactown17:05:57

I have a function that checks a cache, and if nothing is in the cache, it sends a request to a remote data source

lilactown17:05:07

I want to ensure that that behavior is handled correctly

plins17:05:24

hello everyone, not sure if this is the right place to ask, but theres something in clojure similar to elixir's with macro?

lilactown17:05:27

there's a bunch of protocols and other stuff involved. it's not super relevant

lilactown17:05:20

the point is that I have a mock data source I can create by giving it a map, and it will create a promise that resolves with data from that map. I want to make sure that a value from that map is never gotten

the2bears17:05:37

Hmmm... a custom map that performs an observable side effect when accessed? Something like sets a global that can be acted upon with an assert or similar at test time. No idea, really, never seen quite this thing before :O)

the2bears17:05:17

@plins what is elixir's 'with' macro? Don't make us Google it ourselves 🙂

plins17:05:55

sorry, i will elaborate an example

tanzoniteblack17:05:05

@lilactown you could probably accomplish what you want by putting something in the function that fetches from the cache to make sure that it pulled from that, and putting junk data in your map to make sure that the value returned isn't that junk value?

lilactown17:05:06

I don't think there's anything quite exactly like it - Clojure doesn't focus as much on pattern matching

tanzoniteblack17:05:26

if I'm understanding what you're asking for, anyways

lilactown17:05:21

@tanzoniteblack I'm kind of doing that now. it's complicated by the fact that the function doesn't return a value, but an atom

plins17:05:43

@lilactown i really like the [:ok result] and [:error :some-id] indiom, maybe i will write a macro myself

lilactown17:05:47

so right now I'm using a delay to check the value of an atom

lilactown17:05:50

yeah, Erlang/Elixir have a lot of really nice pattern matching & other language features to support that. it is nice when the idiom is so supported by the language

lilactown17:05:41

Clojure's idioms tend more towards exceptions, so you might struggle to use the [status payload] tuple strategy as effectively

💯 4
plins17:05:43

im trying to isolate everything that throws an exception inside a try catch block and then returning the tuple, but I need a way to chain these operations (a monadic bind or something)

lilactown17:05:17

tricky. there are some libraries, like failjure & cats that implement more algebraic structure onto error handling & control flow in clojure

lilactown17:05:45

I guess what I really want is... something that I can pass to (:keyword thing) and thing will have some custom behavior

the2bears17:05:37

You could create a protocol for 'thing' that keywords implement.

Alex Miller (Clojure team)17:05:50

you can use deftype and implement clojure.lang.ILookup

the2bears17:05:02

Or that, sounds better 🙂

lilactown17:05:04

☝️ that's what I needed

Alex Miller (Clojure team)17:05:06

(but honestly I don’t think you should do any of this)

lilactown17:05:19

I've been trying to google what the protocol was 😛

lilactown17:05:33

well now I'm thinking... if I swap that (thing :keyword)... thing can just be a fn

lilactown17:05:10

that might be confusing to people who are ready the code later who are expecting thing to be a map, though

Alex Miller (Clojure team)17:05:38

if I were reviewing this code in Clojure, I’d just tell you to use an exception

lilactown17:05:55

I'm not sure I follow

Alex Miller (Clojure team)17:05:14

reading through the backlog again, I may be crossing the streams with @plins

Alex Miller (Clojure team)17:05:42

you’re after “custom map that performs an observable side effect when accessed” ?

Alex Miller (Clojure team)17:05:25

you could just pass something that is not a map and would thus blow up if you tried to use it like one

Alex Miller (Clojure team)17:05:04

or is there some other behavior that should behave as expected

lilactown17:05:07

just tried it - for some reason it doesn't cause an exception o_O

lilactown17:05:41

there's a bunch of async stuff going on too. also it's in clojurescript, using promises. 😅 the hole deepens

Alex Miller (Clojure team)17:05:43

isn’t that what you expect?

lilactown17:05:01

I would expect when I passed in "NOTAMAP" and it's accessed via ("NOTAMAP" :test) at some point, that it would cause an exception

Alex Miller (Clojure team)17:05:46

well “NOTAMAP” is definitely not a function so, I would agree. but that’s different than (:test “NOTAMAP”) which would just return nil

Alex Miller (Clojure team)17:05:08

(perhaps unfortunately)

lilactown17:05:10

I see, interesting

lilactown17:05:34

it's definitely the former but also TIL

Alex Miller (Clojure team)17:05:02

get is similarly tolerant of non-associative inputs

lilactown17:05:32

so this has uncovered that I do not handle errors correctly in this async mess

lilactown17:05:38

hooray tests!

🎉 8
plins18:05:56

(match (partner-db/get-partner partner-id)
      [:ok partner] :do stuff

      error error)
is there a better way of doing this? like go on if everything is fine, but if there is an error return it?

Alex Miller (Clojure team)19:05:30

You mean like throwing an exception?

devn19:05:57

i can't brain good today:

(let [foos '[{:type foo}
             {:type bar}
             [:abc [:def {:type baz}]]]]
  ;; desired output: (foo bar baz)
  )

devn19:05:47

I want to traverse an arbitrarily nested data structure, returning only non-nil values for :type

dadair19:05:30

reduce + tree-seq + some?

devn19:05:37

i haven't been able to get prewalk or postwalk to do what i want

devn19:05:35

reduce + tree-seq? or just tree-seq? what's the branching and children fn? i toyed with it and failed

souenzzo15:05:38

checkout #specter

bronsa19:05:02

user=> (keep :type (tree-seq vector? identity foos))
(foo bar baz)

devn19:05:08

oyyyyyyy, thank you @bronsa

bronsa19:05:05

I think it's the first time I actually use tree-seq :)

devn19:05:41

i guess i was surprised to see vector? as the branching fn

devn19:05:31

i had tried associative?, but didn't use identity

bronsa19:05:36

you can use sequential? I guess

samedhi20:05:27

I am having trouble calling the .create method in the following code…

(ns inferno.storage
  (:import
   [com.google.cloud.storage BlobId]
   [com.google.cloud.storage BlobInfo]
   [com.google.cloud.storage StorageOptions]))

(defn storage [] (.getService (StorageOptions/getDefaultInstance)))

(def con (storage))

;; Attempting to call "create" in 
(defn upload! [con bucket blob s]
  (let [blobId (. BlobId (of bucket blob))
        blobInfo (-> (BlobInfo/newBuilder blobId)
                     (.setContentType "text/plain")
                     (.build))
        data (.getBytes s "UTF-8")
        opts (into-array [])]
    (.create con blobInfo data opts)))

(upload! con "" "hey.txt" "Hello World!")
;; => java.lang.IllegalArgumentException: No matching method found: create for class com.google.cloud.storage.StorageImpl

Alex Miller (Clojure team)20:05:43

I think due to type erasure that Clojure will see getService as returning an Object

Alex Miller (Clojure team)20:05:08

you might have to help it out with a type hint on con in the .create call

Alex Miller (Clojure team)20:05:41

it looks like maybe that would be ^com.google.cloud.ServiceOptions

Alex Miller (Clojure team)20:05:53

but I don’t actually see a create method on that

samedhi20:05:07

(type con) => com.google.cloud.storage.StorageImpl

samedhi20:05:25

Oh, actually.

samedhi20:05:32

(->> con reflect :members (filter #(= (:name %) 'create)) pprint)
({:name create,
  :return-type com.google.cloud.storage.Blob,
  :declaring-class com.google.cloud.storage.StorageImpl,
  :parameter-types
  [com.google.cloud.storage.BlobInfo
   java.io.InputStream
   com.google.cloud.storage.Storage$BlobWriteOption<>],
  :exception-types [],
  :flags #{:varargs :public}}
 {:name create,
  :return-type com.google.cloud.storage.Bucket,
  :declaring-class com.google.cloud.storage.StorageImpl,
  :parameter-types
  [com.google.cloud.storage.BucketInfo
   com.google.cloud.storage.Storage$BucketTargetOption<>],
  :exception-types [],
  :flags #{:varargs :public}}
 {:name create,
  :return-type com.google.cloud.storage.Blob,
  :declaring-class com.google.cloud.storage.StorageImpl,
  :parameter-types
  [com.google.cloud.storage.BlobInfo
   byte<>
   com.google.cloud.storage.Storage$BlobTargetOption<>],
  :exception-types [],
  :flags #{:varargs :public}}
 {:name create,
  :return-type com.google.cloud.storage.Blob,
  :declaring-class com.google.cloud.storage.StorageImpl,
  :parameter-types
  [com.google.cloud.storage.BlobInfo
   com.google.cloud.storage.Storage$BlobTargetOption<>],
  :exception-types [],
  :flags #{:varargs :public}})

samedhi20:05:16

So, I think I see the method I want to call (the third create).

ghadi20:05:00

Hint: type hint the first argument to upload! as whatever the parent interface to StorageImpl is

ghadi20:05:53

the compiler will either figure it all out or provide you a more specific error message. (don't forget to (set! *warn-on-reflection* true))

ghadi20:05:37

com.google.cloud.storage.Storage

samedhi20:05:14

Sorry, I am paying attention, just have to read about type hints (never used them).

samedhi20:05:56

Ok, I updated the sexp to look like this (defn upload! [^com.google.cloud.storage.Storage con bucket blob s] ...)

ghadi20:05:26

if you reload with warn-on-reflection set, you'll get a better message (probably)

samedhi20:05:43

Ok, give it a shot.

ghadi20:05:44

you only have to typically hint the target of a method call, and the compiler usually works it out. If there in an overload method with different types, you might have to help the compiler disambiguate the differences

ghadi20:05:54

(usually)

samedhi20:05:33

I am wondering about that variadic thing at the end of this method call, which as I currently understand I all using the empty array if I am not using it.

samedhi20:05:46

But my java Array is of type Object, maybe I need to be more specific.

samedhi20:05:58

Ok, this is what I have so far, same error unfortunately…

samedhi21:05:34

Ok, got it

samedhi21:05:45

Updating the gist again in case anyone was looking at that.

samedhi21:05:04

The key was changing (into-array Object []) => (into-array com.google.cloud.storage.Storage$BlobTargetOption [])

samedhi21:05:41

I wonder if that is a general property of java variadic method dispatch, or something special that this library is doing…

samedhi21:05:33

Also, when calling upload! successfully, I got the following two warnings

Reflection warning, /Users/stephen/inferno/src/inferno/storage.clj:18:14 - call to method getBytes can't be resolved (target class is unknown).
Reflection warning, /Users/stephen/inferno/src/inferno/storage.clj:20:5 - call to method create on com.google.cloud.storage.Storage can't be resolved (argument types: com.google.cloud.storage.BlobInfo, unknown, unknown).

samedhi21:05:55

Don’t think those really matter, just leaving them here in case it helps someone.

samedhi21:05:03

On a completely separate note, all of this type safety stuff seems so f&%ing worthless.

Alex Miller (Clojure team)21:05:19

it’s all an illusion :)

Alex Miller (Clojure team)21:05:36

the jvm doesn’t care :)