I'm writing a chat client/server, and have the following code that takes a socket, and gives back a clojure.core.async/channel that can be used to write to the socket more easily.
My problem is, despite being type-hinted, I still get reflection warnings that the call to .write
can't be resolved.
(ns chat.main
(:require [clojure.core.async :as a :refer [>! >!! <! <!! go thread chan]])
(:import [java.net Socket ServerSocket]
[java.io InputStream BufferedReader InputStreamReader OutputStream BufferedOutputStream PrintWriter]))
(set! *warn-on-reflection* true)
(defn new-output-chan [^Socket sock]
(let [^OutputStream out (.getOutputStream sock)
^PrintWriter p-out (PrintWriter. out)
out-chan (chan)]
(go
(while (.isConnected sock)
(let [^String message (<! out-chan)]
(.write p-out message) ; <---------- Here
(.flush p-out)))
(a/close! out-chan))
out-chan))
Gives:
Reflection warning, C:\Users\slomi\IdeaProjects\chat\src\chat\main.clj:44:5 - call to method write on java.io.PrintWriter can't be resolved (argument types: unknown).
I don't know how I could make it any clearer though. Both p-out
and message
are explicitly hinted. Strangely, the call to flush
is fine.
How can I resolve this?
The problem is that go
actually rewrites your code into a state machine (you can inspect the transformation with macroexpand-1
, but the result is pretty lengthy, so I haven't included it here). Unfortunately, it looks like this transformation doesn't preserve the type hint.
Maybe there's a better solution, but if you pull out the call into its own function, you can typehint that, since it won't be rewritten by go
:
(defn new-output-chan [^Socket sock]
(let [^OutputStream out (.getOutputStream sock)
^PrintWriter p-out (PrintWriter. out)
out-chan (chan)
write #(.write p-out ^String %)]
(go
(while (.isConnected sock)
(let [message (<! out-chan)]
(write message)
(.flush p-out)))
(a/close! out-chan))
out-chan))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With