Fork me on GitHub
#clojure
<
2019-12-07
>
lilactown00:12:11

it was hidden by my Emacs window :face_palm:

andy.fingerhut00:12:39

That would have been about my third question :)

andy.fingerhut00:12:03

Window managers with some kind of dock that add an icon for new windows can be helpful in such situations

lilactown00:12:38

I’m on macOS and I did expect it to add an icon to my dock or appear in my list of apps via alt + tab

andy.fingerhut00:12:02

I am on macOS, and when I call (clojure.inspector/inspect-tree [1 2 3 [4 5]]) in a REPL started within a terminal using clj , using Clojure 1.10.1 and OpenJDK 1.8, it does create an icon in the dock that looks like the Java "Duke" mascot

lilactown01:12:32

yeah, I think the way CIDER starts the JVM must hide it

erwinrooijakkers11:12:31

I am trying to get all values out of a core.async channel

erwinrooijakkers11:12:52

I have a program like this:

(defn tst [out]
  (go-loop [[x & xs] (range 5)]
    (cond (seq xs)
          (do (println "now here:" x)
              (>! out x)
              (recur xs))
          :else :exit)))

(def out (chan))
(tst out)
(close! out)
(go (println "value here: " (<! out)))

erwinrooijakkers11:12:16

This prints: > now here: 0 > value here: 0 > now here: 1 > now here: 2 > now here: 3

erwinrooijakkers11:12:49

So when I execute the last statement it retrieves only the first value “now here”

erwinrooijakkers11:12:12

And only then it seems to put on the further xs

erwinrooijakkers11:12:45

How do I also get the 1 2 3 out?

erwinrooijakkers11:12:21

Or how do I properly put them on the out channel so I can retrieve them later?

erwinrooijakkers11:12:21

Hmm maybe not close! it

erwinrooijakkers11:12:43

But I need the value outside a go block

bortexz11:12:38

That is because you are creating an unbuffered channel (chan) , that doesn’t continue execution until the value is retrieved from the “value here: “. If you create a buffered channel like (chan 5) , then all values will fit into the buffer of the channel before later on you decide to retrieve them fron any other place

erwinrooijakkers11:12:57

I thought channels had a buffer of 2000 by default

erwinrooijakkers11:12:12

Still doesn’t work

erwinrooijakkers11:12:16

I want to get the values out with (<!! (async/into [] out))

erwinrooijakkers11:12:22

(defn tst [out]
  (go-loop [[x & xs] (range 5)]
    (cond (seq xs)
          (do (println "now here:" x)
              (>! out x)
              (recur xs))
          :else :exit)))
(def out (chan 2000))
(tst out)
(close! out)
(println "value here: " (<!! (async/into [] out)))

erwinrooijakkers11:12:04

> now here: 0 > now here: 1 > now here: 2 > now here: 3 > value here: [0 1 2 3]

sogaiu12:12:02

@erwinrooijakkers btw, there is #core-async too 🙂

erwinrooijakkers12:12:23

Thanks I’ll ask there

borkdude20:12:45

I want to test a socket server implementation. I used to use netcat for this, but I want to do it in clojure. I've got this now:

(defn socket-command [expr]
  (with-open [socket (.Socket. "127.0.0.1" 1666)
              writer (io/writer socket)
              reader (io/reader socket)
              sw (.StringWriter.)]
    (.write writer (str expr "\n"))
    (.flush writer)
    (.write writer (str ":repl/exit\n"))
    (.flush writer)
    (loop []
      (when-let [l (.readLine ^.BufferedReader reader)]
        (binding [*out* sw]
          (println l))
        (recur)))
    (str sw)))
This works. But additionally I want to test / emulate sending C-d (end of transmission). How do I do this? By closing the writer? That makes the reading raise an exception because this closes the socket.

borkdude20:12:46

does clojure itself have tests for the socket server maybe?

borkdude20:12:59

maybe I should just quit reading when I've seen the expected string

andy.fingerhut20:12:56

I thought that C-d would close the socket without sending any additional data on it, but that was a belief I have rather than a tested hypothesis.

andy.fingerhut20:12:37

What exception do you see thrown while reading? Perhaps existing socket REPL endpoint implementations expect that exception and ignore it?

borkdude21:12:14

ah, my hypothesis seems not correct:

user=> (def s (.Socket. "127.0.0.1" 1666))
#'user/s
user=> (require '[ :as io])
nil
user=> (def w (io/writer s))
#'user/w
user=> (def r (io/reader s))
#'user/r
user=> (binding [*out* w] (println "(+ 1 2 3)"))
nil
user=> (binding [*in* r] (read-line))
"Babashka v0.0.38-SNAPSHOT REPL."
user=> (binding [*in* r] (read-line))
"Use :repl/quit or :repl/exit to quit the REPL."
user=> (.close w)
nil
user=> (binding [*in* r] (read-line))
"Clojure rocks, Bash reaches."
user=> (binding [*in* r] (read-line))
""
user=> (binding [*in* r] (read-line))
"user=> 6"
user=> (binding [*in* r] (read-line))
Execution error (SocketException) at .SocketInputStream/socketRead0 (SocketInputStream.java:-2).
Socket closed

borkdude21:12:24

so you can keep reading when the writer has closed.

borkdude21:12:54

but read-line won't give nil, so I'll have to handle an exception I guess

kenj22:12:29

what am I doing wrong here with into?

(into {} [["a" "b"]])
=> {"a" "b"}
(into {} ['("a" "b")])
Execution error (ClassCastException) at day-6/eval1723 (form-init3777930615038395775.clj:1).
java.lang.String cannot be cast to java.util.Map$Entry

kenj22:12:09

I was expecting the 2nd line to work the same as the first, the difference there just being a vector vs a list

sogaiu22:12:20

@risinglight this is a guess, but it looks like maps handle 2-element vectors as a special case, but not lists: <https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L24_L37> - perhaps some more knowledgeable people can step in and clarify :)

👍 4
dominicm22:12:07

There's an answer floating around in Google about this if you're curious for the background. I can't remember where now. My vague memory is that it's because lists aren't a suitable data structure for this operation.

sogaiu01:12:56

was curious but my spelunking foo was not good enough this round 🙂

dominicm09:12:33

I couldn't either, but it's on our internal chat. Might find it Monday.

🤞 4
dominicm13:12:19

> I guess the only thing to add is that a list of 2 elements is not treated as a valid map entry because it is not indexed (you can't just grab the 0th key “slot” and the 1th value “slot”), you would have to iterate through the key to get to the value.

sogaiu13:12:21

thanks for tracking that down :thumbsup:

sogaiu22:12:12

<https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L75_L89>

sogaiu22:12:05

<https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L6897>

rakyi22:12:24

one alternative would be (apply hash-map '("a" "b" "c" "d"))

kenj22:12:52

I worked around it by passing my collection of tuples through (map vec) first… it just threw me off

kenj22:12:24

(defn parse-input [s]
  (->> s
       (str/split-lines)
       (map #(str/split % #"\)"))
       (map reverse)
       (map vec)
       (into {})))

kenj22:12:11

without the (map vec) in the above function, it blows up with the same error as in the REPL test

dominicm22:12:07

There's an answer floating around in Google about this if you're curious for the background. I can't remember where now. My vague memory is that it's because lists aren't a suitable data structure for this operation.

Cameron23:12:44

As a side note, as I go back and forth between Clojure and Elisp, I become more and more grateful for the vector being used as the primitive for contiguous collections over overloading the list, although its hard to really isolate all the intuition in my head as to why (beyond the reasons I know from a less intuitive, analytical perspective)