clojuretype-inferencecursive

Why is Clojure unable to infer this def type?


I was writing a client/server test, and ran into something unexpected. In the following code, the port argument of the Socket constructor isn't able to be inferred:

(ns second-try.test.client
  (:import [java.net Socket]))

(def port 5555)

(defn -main []
  ; "Cannot disambiguate overloads of Socket"
  (let [sock (Socket. "127.0.0.1" port)]))

The type of the first argument should be obvious since I'm passing a literal. I would think the type of the port would be obvious too since again, it's just a literal; albeit one tucked away behind a def.

For some reason though, it can't figure out the type of port. I can remedy it by putting an annotation on either the def, or in front of the argument, but why is this necessary? Shouldn't it be obvious to it what the type is?


Solution

  • It's not really possible to infer the type of the value stored in a var in Clojure, because a var can be re-defined at any time.

    However, Clojure shouldn't have any problem determining the type at run-time and, although it will require the use of reflection to disambiguate at run-time, the code in question should (and does) run.

    The error appears to be related to Cursive: https://stackoverflow.com/a/32473508/440294

    Adding a type-hint ... to specify which overload you expect to use would remove the need for reflection and hopefully calms Cursive down.

    In your case, I'd try something like:

    (defn -main []
      ; "Cannot disambiguate overloads of Socket"
      (let [^int p port
            sock (Socket. "127.0.0.1" p)]))