Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Clojure 1.3 say that variables aren't declared dynamic when I have declared them to be dynamic? [closed]

I'm porting working Clojure code (in a Leiningen project) from 1.2 to 1.3 and having problems. In addition to the code itself no longer working, I'm getting dozens of warning messages like this one:

Warning: *tooltip-width* not declared dynamic and thus is not dynamically rebindable, 
but its name suggests otherwise. Please either indicate ^:dynamic *tooltip-width* 
or change the name.

This is happening even though I have already made what look like the correct modifications to vars that I'm using to maintain state. For the error above, for example, the code already includes this:

(def ^:dyanamic *tooltip-width*   (* 1.8 *slip-width*))

I get these errors in two places: first, from the command line, as a result of executing lein swank; and second, from the Emacs REPL, after compiling my core.clj file using C-c C-w.

To be absolutely complete, here is my project.clj file:

(defproject infwb "1.0.0-SNAPSHOT"
  :description "an evolving, experimental workspace for manipulating infocards"
  :main infwb.core

  :dependencies [[org.clojure/clojure "1.3"]
             [seesaw "1.2.1"]
         [org.clojars.gw666/sxqj "beta2"]
         [org.clojars.gw666/piccolo2dcore "1.3"]
         [org.clojars.gw666/piccolo2dextras "1.3"]
         [com.miglayout/miglayout "3.7.4"]
         ]
  :dev-dependencies [[swank-clojure "1.3.2"]
             [org.clojars.weavejester/autodoc "0.9.0"]]
  :autodoc {:name "Infocard Workbench (InfWb)",
        :web-src-dir "https://github.com/gw666/infwb/blob"})

In addition to getting my code working, I'd like to understand why I'm getting these errors and why I'm getting them in both places. Thanks for your help.

like image 725
Gregg Williams Avatar asked Nov 21 '11 23:11

Gregg Williams


2 Answers

It's a simple typo.

(def ^:dyanamic ...

should be:

(def ^:dynamic ...

Happens to us all!

like image 106
Scott Avatar answered Sep 28 '22 12:09

Scott


You might want to consider using refs or atoms instead of vars to maintain state.

To quote the Clojure documentation:

Vars provide a mechanism to refer to a mutable storage location that can be dynamically rebound (to a new storage location) on a per-thread basis.

(Emphasis mine.)

Vars can be set to a new value (for the current thread) with the binding macro. Up to Clojure 1.2 any var could be rebound like this, but since Clojure 1.3 vars need to be explicitly declared as ^:dynamic to allow this. (As far as I know, the reason is a drastic speed-up of var look-ups for the common case of no rebinding.)

It is a common convention (but nothing more) to give vars that are intended to be rebound names like this: *foobar*. Because of this convention, the compiler gives you a warning when it sees a var named like this that is not declared dynamic.

To sum up:

  • If you just want to declare a value that does not change during runtime, use a var and drop the *'s around the name.
  • If you want to change the value on a per-thread basis, declare the var dynamic.
  • If you want to maintain global state (not per-thread), use one of the other referential types: atom, ref (if you need transactions) or agent (for asynchronous change).
like image 23
Christian Berg Avatar answered Sep 28 '22 12:09

Christian Berg