On Wed, Jul 8, 2009 at 11:37 PM, Phil Hagelberg<p...@hagelb.org> wrote: > > Robert Campbell <rrc...@gmail.com> writes: > >> The main reason this is an issue for me is during development I >> sometimes find I need another library added to my classpath. Right now >> the only way I know how to modify the classpath in Emacs is to change >> the .emacs file with an add-to-list 'swank-clojure-extra-classpaths >> and reboot. I think my looking for an image solution might be a >> cop-out itself; I need to learn Emacs better so I can figure out how >> to modify the classpath without rebooting. > > Unfortunately this is impossible due to the way the classloaders in the > JVM work; you can't modify your classpath at runtime and have it work > consistently. > > The solution I've settled on is to have a static classpath; no matter > what the project is, my classpath is always the same: > src/:target/dependency/:target/classes/:test/ > > When you need to add a new library, instead of putting the jar on the > classpath, just unpack the jar in the target/dependency directory. Then > you can access it without restarting the JVM. >
</snip> > You don't run into this problem with Java dev in Eclipse because Java > doesn't have a REPL. I agree that it sucks though. Unpacking your > dependencies all in one place is a lot nicer anyway; no restarts required. Uhm, that's not exactly true. The classpath is what you give your VM as initial set of available classes to what it defines internally. The definition is static, but there are other ways to inject code into the class lookup mechanism inside the JVM which is where the classloaders come in. It's perfectly fine to reload any class at runtime, including the ones in a jar if they are defined in a classloader that you can control. There are two problems you have to overcome though. 1) If you want to change classes that are already loaded, one strategy is to hot swap the code (either via JVMTI, that's what you can do when you're in debug mode in an IDE, or you use JavaRebel (commercial), which goes a bit further in what you're able to redefine without killing the JVM, and losing state). Not sure if that's needed for Clojure code, since I haven't looked much at the bytecode so far, but it's really handy for Java and Scala for instance). 2) If you really need to add new things to the classpath (e.g. a new Jar), or you just want to reload a whole bunch of stuff, then you have to ditch the classloader that has these classes loaded (does not apply if you're adding new stuff), and add a new classloader that finds the new dependency at runtime. This is not that hard to do (check classloader javadoc), but it has quite a few cornercases, so it's not recommended to try it adhoc. There are systems that implement the whole system for you. Eclipse itself (the IDE, not the projects in it) can install plugins at runtime (although it asks you whether you want to restart), as can Maven (plugins are installed at runtime). The mechanism that supports this in Eclipse is OSGi (in Maven it's homegrown - classworlds), which is a nifty specification for dynamic service management inside the JVM. It can do a lot of things, but what is most interesting here is that it tracks versioned dependencies of runtime components. Think Maven or Ivy at runtime, and it's dynamically loading/unloading code based on what you specify. All of the OSGi implementations feature a management console (a REPL) where you can interact with the system at runtime (load and unload dependencies, it will warn if there are unmet dependencies etc.). I think making Clojure work well with OSGi is under 'longterm' on the roadmap, but I don't know what the current status is. I'm definitely giving it a vote though. Just to be clear, the classpath you define on the commandline is just a shortcut to define a classloader that looks up classes inside the jars and directories you define on the commandline. If you have your own classloaders (instantiated) you can load your code from a special directory (that's what the webcontainers (tomcat etc.) do to support hot redeployment of apps), the web (that's what applets do), a database (don't know who's doing that), an uncompiled script file (that's what scripting languages do unless they have precompiled to class files), or any other storage you can think of. The only requirement for a classloader is to return a bytearray that is valid java bytecode according to the spec, and it can only load the code once (it's cached after that, that's why you have to ditch the classloader). (And although the -cp argument supports wildcards since Java 1.6, they are expanded early and cannot be reevaluated during runtime :( ) More information available at: http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html So depending on your approach and what you want to be able to do (redefine/reload or add), it's a bit of work. The easiest thing is to unpack your dependencies, but for my taste it's pretty messy. Cheers, Daniel (today seems to be the day of long posts. Sorry guys) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---