I'm binding an instance to a Var:
(ns org.jb
(:import (java.awt PopupMenu
TrayIcon
Toolkit
SystemTray)
(javax.swing JFrame
Action)))
(def ^:dynamic popupmenu)
(def ^:dynamic image)
(def ^:dynamic trayicon)
(def ^:dynamic tray)
(defn start-app [appname icon]
(binding [popupmenu (new PopupMenu)
image (.. Toolkit (getDefaultToolkit) (getImage icon))
trayicon (new TrayIcon image appname popupmenu)
tray (. SystemTray getSystemTray)]
(. trayicon setImageAutoSize true)
(. tray add trayicon)))
(start-app "escap" "res/escap_icon.png")
Error:
ClassCastException clojure.lang.Var$Unbound cannot be cast to java.awt.Image org.jb/start-app (org\jb.clj:17)
I am predefining the Var with
(def image)
even tried
(def ^:dynamic image)
Unable to understand what is expected from the message.
Using let in place of binding works within the lexical scope however. However want to achieve dynamic binding.
All I see here is an empty binding
form with no code. The variable binding goes out of scope once you leave the binding
form. Based on your error message, it looks like you're trying to use the image
var outside of the binding form. You need to make sure that all code that uses image
is placed inside the binding.
So, instead of this:
(binding [*image* (.. Toolkit (getDefaultToolkit) (getImage "icon.png"))])
(display-image *image*)
Do this:
(binding [*image* (.. Toolkit (getDefaultToolkit) (getImage "icon.png"))]
(display-image *image*))
Another possible issue is that the binding expressions are evaluated in parallel whereas expressions in let
are evaluated in sequence. This means that if you're binding multiple vars and one depends on the other, it will use the value that was in scope before the binding was evaluated.
So, this will throw an exception:
(def ^:dynamic *a*)
(def ^:dynamic *b*)
(binding [*a* 2
*b* (+ *a* 3)]
(+ *a* *b*)) ; => ClassCastException clojure.lang.Var$Unbound cannot be cast
; to java.lang.Number clojure.lang.Numbers.multiply
; (Numbers.java:146)
Instead you would have to use nested binding forms:
(binding [*a* 2]
(binding [*b* (+ *a* 3)]
(+ *a* *b*))) ; => 8
Note that I've placed "earmuffs" around the var name. This is the naming convention for dynamic vars in Clojure, so other people can easily tell that it's dynamic. Also, if you're able to dynamically bind a var without declaring it with ^:dynamic
metadata, that means you're using a pretty old version of Clojure. I'd suggest you upgrade - 1.5.1 is the latest stable release.