debuggingclojure

Clojure compile-time escape mechanism


The language Forth offers a "compile-time" escape mechanism where code can be executed immediately, while the compiler is running (not at run-time). You can include print statements, for example, to debug tricky syntax or type errors).

Does Clojure have anything similar? I am getting a compile-time IllegalArgumentException in one of my function calls and would like to add a compile-time print statement to determine the argument type ((.getClass)).

Thanks.

UPDATE: Here is the complete defn that is failing compilation:

(ns my.ns.name
  (:gen-class
   :main true)
  (:use
   [clojure.contrib.str-utils2 :only (join)])
  (:import
   [java.io PrintWriter]
   [java.net URL]
   [java.util.concurrent Executors]
   [java.util.jar Manifest]
   [org.apache.commons.cli CommandLine HelpFormatter Options Option ParseException PosixParser]))

(defn set-version
  "Set the version variable to the build number."
  []
  (def version
    (-> (str "jar:" (.. my.ns.name (getProtectionDomain)
                                   (getCodeSource)
                                   (getLocation))
                    "!/META-INF/MANIFEST.MF")
      (URL.)
      (.openStream)
      (Manifest.)
      (.. getMainAttributes)
      (.getValue "Build-number"))))

This defn works:

(defn set-version
  "Set the version variable to the build number."
  []
  (println (str (.getClass my.ns.name)))
  (def version
    (-> (str "jar:" (-> my.ns.name (.getProtectionDomain)
                                   (.getCodeSource)
                                   (.getLocation))
                    "!/META-INF/MANIFEST.MF")
      (URL.)
      (.openStream)
      (Manifest.)
      (.. getMainAttributes)
      (.getValue "Build-number"))))

Solution

  • Printing the class of things during compilation is pretty restricted to special cases. You will mostly get Symbols and Seqs. Only literals have a meaningful type during compilation. You can execute arbitrary code during compilation via macros.

    (defmacro debug-type
      [x]
      (println (type x))
      x)
    

    However as I said: this will normally not be very helpful. And no: in general you cannot wrap x in an eval, eg. if x is a symbol refering to a let-local.

    EDIT: Update for updated question.

    (def version
      (-> (str "jar:" (-> *ns* (.getProtectionDomain)
                               (.getCodeSource)
                               (.getLocation))
                      "!/META-INF/MANIFEST.MF")
        (URL.)
        (.openStream)
        (Manifest.)
        (.getMainAttributes)
        (.getValue "Build-number")))
    

    Try this. There is no need for a function. def inside defn should ring alarm bells.