Thursday, January 12, 2012

namespace '%s' not found after loading '%s'

While working through Rob Rowe's introduction to C# / Clojure interop, I ran into the following error, which illuminates something useful about Clojure's expectations when it comes to namespaces. Much could be said about this topic, but I will leave that to the experts and just explain the problem I was having and how I solved it.

In Rob's post, he uses some sample code that calculates batting averages and standings for baseball teams. His Clojure code begins with the namespace directive "(ns one)", which tells the Clojure compiler into which namespace to register these functions. When testing out his code, I created a project named Baseball, which creates a file called baseball.clj:


















When I tried to build and run his code, I got the following error:

I chose "Debug the program" and was given the choice of debugging in the currently running instance of Visual Studio or starting a new one. I chose the currently running instance:

  
And got this:

 
Not very helpful. But when I clicked View Detail, I was presented with both an error message and, more usefully, a stacktrace:

Here is the stacktrace in full:

   at clojure/core$fn__13329$throw_if__13331.__invokeHelper_2v(clojure/core$fn__13329$throw_if__13331_base this, Object pred, Object fmt, Object args) in core.clj:line 4684
   at clojure/core$fn__13329$throw_if__13331.doInvoke(Object , Object , Object )
   at clojure/core$fn__13368$load_one__13370.__invokeHelper_3(clojure/core$fn__13368$load_one__13370_base this, Object lib, Object need_ns, Object require) in core.clj:line 4732
   at clojure/core$fn__13368$load_one__13370.invoke(Object , Object , Object )
   at clojure/core$fn__13461$compile__13463.__invokeHelper_1(clojure/core$fn__13461$compile__13463_base this, Object lib) in core.clj:line 4916
   at clojure/core$fn__13461$compile__13463.invoke(Object )
   at clojure.lang.Var.invoke(Object arg1)
   at BootstrapCompile.Compile.Main(String[] args)

Now I was getting somewhere: The highlighted lines were the call just before the error was thrown, so by looking there I should be able to get some idea of what went wrong. So I re-ran the program and this time chose to open a new instance of Visual Studio. I was asked to supply the source code for the lines I was debugging. Fortunately, the Find Source dialog started me out just one folder away from the source by default, in C:\Users\daniel_cotter\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\jmis\vsClojure\1.1.0\Runtimes\1.2.0:

I chose clj-source and was presented with this much more helpful view (I've skipped to line 4732, where the error was thrown:

Lo and behold, the exact error I was getting. The line above it says, almost literally, "throw an error if a namespace is needed and not found." Thinking about this and looking at the code that was causing the error, I realized that the namespace had been set to "one" (remember "(ns one)"?). I went back and changed the namespace to "baseball" to match the filename ("baseball.clj"), recompiled, and it worked:
















Summary
The lesson I'm taking from all this? Be careful with your namespaces. For those of us accustomed to .NET's liberal namespacing conventions (basically, a namespace block is all you need, and it doesn't have to the filename), Java's conventions are much stricter, and Clojure seems to follow suit, even when in a .NET environment. Personally, I have long found namespacing issues one of the more confusing parts of Clojure, probably because I am not well-versed in Java.

No comments:

Post a Comment