Monday, December 15, 2008

Goddamn ant macosx xml problem


[ chrisn chris-nuernbergers-macbook-pro ~/dev/editor/lambinator ] ./buildme.sh
Buildfile: build.xml

init:

compile_lambinator:
[java] Compiling lambinator.experiment to /Users/chrisn/dev/editor/lambinator/classes
[java] Compiling lambinator.ui to /Users/chrisn/dev/editor/lambinator/classes
[java] java.lang.ExceptionInInitializerError (ui.clj:1)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:747)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:201)
[java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:104)
[java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
[java] at org.apache.tools.ant.Task.perform(Task.java:348)
[java] at org.apache.tools.ant.Target.execute(Target.java:357)
[java] at org.apache.tools.ant.Target.performTasks(Target.java:385)
[java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
[java] at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
[java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[java] at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:698)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:199)
[java] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
[java] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)
[java] Caused by: java.lang.ExceptionInInitializerError (ui.clj:1)
[java] at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2684)
[java] at clojure.lang.Compiler$BodyExpr.eval(Compiler.java:3631)
[java] at clojure.lang.Compiler.compile(Compiler.java:4564)
[java] at clojure.lang.RT.compile(RT.java:362)
[java] at clojure.lang.RT.load(RT.java:404)
[java] at clojure.lang.RT.load(RT.java:376)
[java] at clojure.core$load__4557$fn__4559.invoke(core.clj:3427)
[java] at clojure.core$load__4557.doInvoke(core.clj:3426)
[java] at clojure.lang.RestFn.invoke(RestFn.java:413)
[java] at clojure.core$load_one__4520.invoke(core.clj:3271)
[java] at clojure.core$compile__4563$fn__4565.invoke(core.clj:3437)
[java] at clojure.core$compile__4563.invoke(core.clj:3436)
[java] at clojure.lang.Var.invoke(Var.java:327)
[java] at clojure.lang.Compile.main(Compile.java:52)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
[java] ... 20 more
[java] Caused by: java.lang.ExceptionInInitializerError
[java] at com.trolltech.qt.QtJambiObject.(QtJambiObject.java:57)
[java] at java.lang.Class.forName0(Native Method)
[java] at java.lang.Class.forName(Class.java:164)
[java] at clojure.core$import__3583.doInvoke(core.clj:1600)
[java] at clojure.lang.RestFn.applyTo(RestFn.java:142)
[java] at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2679)
[java] ... 39 more
[java] Caused by: java.lang.RuntimeException: Loading library failed, progress so far:
[java] Unpacking .jar file: 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java] Checking Archive 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java]
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadNativeLibrary(NativeLibraryManager.java:428)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadQtLibrary(NativeLibraryManager.java:352)
[java] at com.trolltech.qt.Utilities.loadQtLibrary(Utilities.java:137)
[java] at com.trolltech.qt.Utilities.loadQtLibrary(Utilities.java:133)
[java] at com.trolltech.qt.QtJambi_LibraryInitializer.(QtJambi_LibraryInitializer.java:53)
[java] ... 45 more
[java] Caused by: java.lang.RuntimeException: Failed to unpack native libraries, progress so far:
[java] Unpacking .jar file: 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java] Checking Archive 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java]
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack(NativeLibraryManager.java:365)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadLibrary_helper(NativeLibraryManager.java:434)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadNativeLibrary(NativeLibraryManager.java:423)
[java] ... 49 more
[java] Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found
[java] at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:113)
[java] at com.trolltech.qt.internal.NativeLibraryManager.readDeploySpec(NativeLibraryManager.java:496)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpackDeploymentSpec(NativeLibraryManager.java:521)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack_helper(NativeLibraryManager.java:389)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack(NativeLibraryManager.java:360)
[java] ... 51 more
[java] --- Nested Exception ---
[java] java.lang.ExceptionInInitializerError (ui.clj:1)
[java] at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2684)
[java] at clojure.lang.Compiler$BodyExpr.eval(Compiler.java:3631)
[java] at clojure.lang.Compiler.compile(Compiler.java:4564)
[java] at clojure.lang.RT.compile(RT.java:362)
[java] at clojure.lang.RT.load(RT.java:404)
[java] at clojure.lang.RT.load(RT.java:376)
[java] at clojure.core$load__4557$fn__4559.invoke(core.clj:3427)
[java] at clojure.core$load__4557.doInvoke(core.clj:3426)
[java] at clojure.lang.RestFn.invoke(RestFn.java:413)
[java] at clojure.core$load_one__4520.invoke(core.clj:3271)
[java] at clojure.core$compile__4563$fn__4565.invoke(core.clj:3437)
[java] at clojure.core$compile__4563.invoke(core.clj:3436)
[java] at clojure.lang.Var.invoke(Var.java:327)
[java] at clojure.lang.Compile.main(Compile.java:52)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:217)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:152)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:747)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:201)
[java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:104)
[java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java] at java.lang.reflect.Method.invoke(Method.java:585)
[java] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
[java] at org.apache.tools.ant.Task.perform(Task.java:348)
[java] at org.apache.tools.ant.Target.execute(Target.java:357)
[java] at org.apache.tools.ant.Target.performTasks(Target.java:385)
[java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
[java] at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
[java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
[java] at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:698)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:199)
[java] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
[java] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)
[java] Caused by: java.lang.ExceptionInInitializerError
[java] at com.trolltech.qt.QtJambiObject.(QtJambiObject.java:57)
[java] at java.lang.Class.forName0(Native Method)
[java] at java.lang.Class.forName(Class.java:164)
[java] at clojure.core$import__3583.doInvoke(core.clj:1600)
[java] at clojure.lang.RestFn.applyTo(RestFn.java:142)
[java] at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2679)
[java] ... 39 more
[java] Caused by: java.lang.RuntimeException: Loading library failed, progress so far:
[java] Unpacking .jar file: 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java] Checking Archive 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java]
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadNativeLibrary(NativeLibraryManager.java:428)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadQtLibrary(NativeLibraryManager.java:352)
[java] at com.trolltech.qt.Utilities.loadQtLibrary(Utilities.java:137)
[java] at com.trolltech.qt.Utilities.loadQtLibrary(Utilities.java:133)
[java] at com.trolltech.qt.QtJambi_LibraryInitializer.(QtJambi_LibraryInitializer.java:53)
[java] ... 45 more
[java] Caused by: java.lang.RuntimeException: Failed to unpack native libraries, progress so far:
[java] Unpacking .jar file: 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java] Checking Archive 'qtjambi-macosx-gcc-4.4.3_01.jar'
[java]
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack(NativeLibraryManager.java:365)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadLibrary_helper(NativeLibraryManager.java:434)
[java] at com.trolltech.qt.internal.NativeLibraryManager.loadNativeLibrary(NativeLibraryManager.java:423)
[java] ... 49 more
[java] Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found
[java] at javax.xml.parsers.SAXParserFactory.newInstance(SAXParserFactory.java:113)
[java] at com.trolltech.qt.internal.NativeLibraryManager.readDeploySpec(NativeLibraryManager.java:496)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpackDeploymentSpec(NativeLibraryManager.java:521)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack_helper(NativeLibraryManager.java:389)
[java] at com.trolltech.qt.internal.NativeLibraryManager.unpack(NativeLibraryManager.java:360)
[java] ... 51 more


Solution:
sudo mv /usr/share/ant/lib/xercesImpl.jar /usr/share/ant/lib/xercesImpl.jar.back

Don't ask me how I figured that one out.

Sunday, December 14, 2008

Clojure Projects

I don't really know how to start this other than to look at various ways you can create functionality in a clojure project and attempt to categorize them in some productive way.

The first I want to talk about is the repl. Hopefully you have had the pleasure of working with a good repl setup (SLIME's is the best I have ever used, have you seen better?). REPL stands for read-eval-print-loop. It looks like a command prompt and you type in some stuff and immediately see what the result is. This is similar to when you break in a debugger and you can both analyze values *and* do edit and continue.

I am going to out on a limb here and state that the REPL is the fastest way to add new functionality. You type in a couple statements and you see, right after you type them if it worked or not. This is like Christmas. It is a fucking blast if you have never used it; trust me. It feels weird at first but you just have to use it for a couple days and you will be amazed at how much stuff you get to work. The rate you can add functionality to a new system is directly related to the rate that you can get feedback as to the correctness of this functionality. Typed languages use the static typing system to give you a little faster feedback but nothing means anything until the bits are actually moving; thus the repl is the best. It is more fun than diagnosing hindley-milner errors anyway.

OK. The problem with the repl is that you would have to type in your program all the time. So you have files where you can save the information that you can dynamically load into the repl. You can use either (load-file "fname") or you can use slime-compaile-and-load-file from emacs. This is almost as much fun as the repl and a lot more repeatable. The file is still dynamically loaded but at least you can replace sets of functionality at one, easily.

Next we can compile a file and put it into a jar file; or more generally some compilation unit. These are *not* dynamically loadable to my knowledge; thus if you want a program to run for a long time you will load the jar files once and then you are off. Hopefully the program is completely correct and never needs runtime updates.

Jar files are more easily reusable and distributable than stand alone text files. They also protect your IP to some extent although I really don't give a shit about that.

So we have three levels of adding code to the system, in order of ease of mutability. Repl, repl-loaded, and jar'd. So how do we set up a system that makes all this cool?

Well, lets say we have a set of .clj files. We want an ant project that will compile and jar up all of them. I will set this up in a second.

Now, we have to have this jar file path in our classpath somehow. You can either add it via (set-classpath) or you can add it to the java "cp" startup argument.

Now we find some function is wrong in this jar file. Can we dynamically replace this function in a running system? Well, assuming it is reference via 1 level on indirection then yes, we can. This is what the whole environment and "defn" system gets you; I am assuming. But this requires a test.

Basically, if I can create a jar file and then replace some of its functionality in the running system then I am golden; I can have fast, precompiled code *and* I can update the system and try out fixes and new ideas dynamically. I believe, due to the way that clojure's Vars work that I can get this stuff running. But, hope is not a strategy so lets try some of this out.

The first step is to make a jar file out of some clojure file. In the simplest case, I have a clojure file and has a single function in some namespace, and then I jar it up using ant. Next I add it to my classpath and load it into the repl, checking that it works. Finally I replace said function somehow using the repl.

There is one guaranteed caveat that was there in common lisp and it is here too. If you create a closure dynamically this won't be replaced if you load a new file. Thus you need to figure out what level of dynamic functionality you want and avoid closures where necessary, or create closures that immediately call into the namespace vars.

So here we go. Into the lambinator directory and create a subdirectory called src/experiment

OK, copied clojure-contrib's jar file (after actually getting it to produce useful output, you have to tell ant where clojure.jar is). Got the dynjar.clj file compiling into a class directory and having classes shoved into a jar file. At this point I am now as good at clojure as I ever was at java.

I have to update my ~/bin/clojure script to add this jar file to my classpath. I know this will change per project but emacs needs this command; I could perhaps have project-specific .emacs files but I am really not that ambitious.

In my test file, I have one function that returns an integer, and another function that returns the result of the first. Now the test is that if I load the jar file and mess around with the repl I should be able to get the second function to return a new value by replacing the first.

So:
a -> 5
b -> a -> 5

In repl, I will change a to return anything but 5. If this works, then I can dynamically update my running program with new stuff!

Lets see what happens:

Hell happened. Jar hell.

load-file does the equivalent of import and require on all the objects in the file. This was not quite what I expected.

I will update this post later when I have much more information.

Getting emacs working

Looked through the clojure-mode source for some good stuff:

unfortunately, clojure-load-file doesn't seem to work due to:
comint-get-source, and then after I start slime *inferior-lisp-proc*.

slime-load-file worked just fine. I wonder if there is a slime-load-all-out-of-date-files. That would be damn useful.

Some shizzle you should know

OK, so something I use a lot in other editors is bookmarking facilities.

So, in emacs we have two functions that I really care about: bookmark-set and bookmark-jump.

So, the idea is to set a point in a given file you know you will need later. You name these so they are unique.

A bookmark is a fully named entity, so these commands ask you for a name.

set: C-x r m

jump: C-x r b

The next thing I use all the time are registers if I have access to them. Basically, I want to select a bit of text and shove it into some named variable I will reuse in different contexts. Registers in emacs are single-character named entities you can put text (and other things) into and get it out of.

These commands will ask for a single character register name to place information into or get it from.

(select region then..)
copy: C-x r s
paste: C-x r i

In general, try to get by without using copy/paste. It *really* is the work of the devil. In any form.

OK, down to the basics. Remember this is aquamacs...
aquamacs-isearch-forward A-f
aquamacs-repeat-isearch , A-g
aquamacs-repeat-isearch-backward , A-G
isearch-backward C-r
isearch-forward , C-s


Don't forget basic navigation, either:
C-p
C-n
C-b
C-f

Finally, I put these two lines in my .emacs file.

(global-set-key [f4] 'slime-compile-and-load-file)
(global-set-key [f3] 'find-name-dired) //This one is *super* useful in larger projects

Trying out the various slime functions, they don't appear to work very well. The awesome ones are 'slime-who-calls and stuff like that; but anyway...

Well, we have hit the point of somewhat diminishing returns. Thus in the next post we will look at the next steps of a non-trivial clojure project.

Saturday, December 13, 2008

Clojure App dev, step 1 -> repl-QT-repl-QT

The goal of this step is to ensure you can start a qt frame from the repl, switch to qt's event handling (thus leaving the repl) but get back to the repl using a button.

This is critically important; I need to be able to run the application and then update it dynamically *without* restarting anything. I can't tell you how many times, while debugging something like mouse picking or moving objects around in 3d space I had to break into the debugger, then check out what is going wrong. Next I would make an attempt to fix, recompile, reload the presentation and then repeat. Over and over and over and fucking over again. And again. What I would like is that I can see a given function isn't working correctly; I just update the function definition *while I am running the editor*. This is goddamn important. With this working complex, really useable features are much easier to get working correctly.

OK, so here we go!

It should look like:

(start from repl)
open qt frame with one button, return to repl.
switch to qt's event handling thus effectively leaving the repl
push a button and return to repl *without* closing frame
add a menu item to the existing frame, thus ensuring we can mutate the datastructure and get a good update
exit main frame; thus going back to repl.
see what the state of the main frame is; we may be able to open it

This relies on one key assumption: that I can exit qt's event handing without closing the window. I believe I can but I don't know.

If this assumption doesn't hold then I can always store, latently, the commands for creating the UI. Then when I want to repl around with shit I can destroy the entire UI, update the commands to add new elements, and re-create. This is heavy-handed and rude but it might work. It will remove perhaps 30-40% of the functionality that want, however so I will really try to avoid this.

Reading the QT documentation, it looks like you call QApplicationCore.exec() to get things going and then you can call QApplicationCore.exit() in order to return from the event loop. So your return-to-repl button should just call exit, perhaps. There is also a processEvents call that you could call. Essentially, you could loop over calling process events and have your button set a global that tells you to stop. But if exit works then that is the sweetest.

Simple clojure QT example

This should get me started. There is something really weird when you are learning a new language. You don't know how to create a hash, or vector, and it seems every character you type is wrong. It takes a couple days before you (or perhaps just I) get things going. On the other hand, this level of comfortability with the language has benefits. You focus far more on algorithm than details; this leads to better code.

For example, if you lived in C for all your life and was asked to do something one of the first things you would visualize or plan out would be the memory access system because the most complex part of most C programs is based around memory handling; at least as much as what the program is meant to do. It takes a few other languages with garbage collection before you begin to think at a higher level and then work down to the memory level if you have to.

Side tracked:

BillC figured this all out first
This too. It hasn't worked for me yet, though

Well, this blows. I have been trying to diagnose an error for quite some time now, it looks like:

[Thrown class java.lang.ExceptionInInitializerError]

0: com.trolltech.qt.QtJambiObject.(QtJambiObject.java:57)
1: java.lang.Class.forName0(Native Method)
2: java.lang.Class.forName(Class.java:169)

Checking shit out, it isn't immediately clear what is going on. Time to research how to debug this error....

The demos run just fine, so I know it is possible to run applications. Trolltech -helpfully- included a binary starter to the demos so I can't easily see what is going on.

Holy shit that hurt!

Why God Why Doesn't It Work?!?1!1?

**Don't use JDK 6**

Nice, 2 hours of fucking around with java madness. I finally figured out the magic google code that would find the problem exactly:

java.lang.UnsatisfiedLinkError libQtCore.4.dylib

So I need to amend my other post.

Some more things are working. It appears that QApplication.exit actually closes all open widgets. This isn't exactly what I want. So I will just call process events from a loop and have a button set a variable to break out of the loop.

Thus I would like to be able to define a variable in the namespace that is something like "process_events_running" and have the single button in my application set it to false. Then I will provide a custom exec function that calls process in a loop checking that variable.

The simples way to do this would be a closure. I don't immediately see how to do this, but I remember rich hickey stating that lambdas are "ICallable" or something like that. I know that the signal system in QTJambi uses reflection, so if I just pass in a closure as the "this" argument to connect, and pass in the function named call on the icallable I may be able to get somewhere. The interface is Callable:

user> (lambda `(println "hello"))
; Evaluation aborted.
user> (fn [] (println "hello"))
#
user> (set x (fn [] (println "hello")))
; Evaluation aborted.
user> (def x (fn [] (println "hello")))
#'user/x
user> (. x call)
hello
nil
user> x
#
user> (x)
hello
nil
user>

Still not finished, but I need some food.

OK, nice microwave pizza and I am back.

So, passing in a closure to connect works fine. I do it like this:

(defn exec []
(def exec_var 1)
(while
(== exec_var 1)
(QApplication/processEvents)))

(defn create_app_frame []
(ensure_app_init)
(let [app (QApplication/instance)
button (new QPushButton "Go Clojure Go")]
(.. button clicked (connect (fn [] (def exec_var 0)) "call()"))
(doto button
(.resize 250 100)
(.setFont (new QFont "Deja Vu Sans" 18 (.. QFont$Weight Bold value)))
(.setWindowTitle "Go Clojure Go")
(.show))
button)) ;return the button for further reference

Now I need things to sleep because I am chewing up CPU by calling process events over and over again. There is a hasPendingEvents call; so now all I need is how to make the system sleep in a platform independent way. Java has Thread.sleep in the language and that is that.

I didn't mess with the datastructures of the frame yet (mainly because I just have a button). But I have a QT app, running from the repl and most importantly returning to the repl at the push of a button. I had to do a lot of work for this first app; get emacs working, run up against problems with the mac java implementation interacting with QT, and learn a little bit of clojure (which was the best part). The benefits are huge, though, because QT is a good platform to move forward on and because clojure is an order of magnitude more powerful than java; and I personally believe that developing from the repl is much more powerful than developing from a compile/run standpoint.


At this point, I would love to upload all files related to this. I can't, so I started a github project where I will put all the code.
Git R Dun

OK, to quickly review what you will need to get shit working:

QT - I had version 4.4.3_01
java - 1.5.0
aquamacs emacs
git,svn,cvs, and the latest versions of:
(svn from various other places)
clojure
clojure-contrib

(from joshu's git repository)
clojure-mode
swank-clojure

(cvs. I wish this project had some better regression testing systems)
slime

Watch every single presentation here:
Rich Hickey

Watch them again until you really get it.

Next up will be an emacs post; I need to remember how to use/navigate within emacs and how to integrate with slime better.

Java application development

When writing a new application in Java you really have several choices. You can use the SWT, swing, and perhaps QT to name a few. On Linux, you can probably use some GTK wrapper but I don't know.

Everyone wants extensible applications, but what does this really mean? The answer to this question is kind of important. There is eclipse-style plugin architecture; plugin with a capital P. You will not write a better plugin architecture than this. You may write one that is more minimal that suites just exactly your needs but it won't be better for sure.

I am stuck at this point. I would in some cases like to build an application off of the eclipse system but there is something about it I don't like; mainly the steep learning curve. My application will not look like eclipse and I am not certain it should use the workspace API. If you don't use the workspace plugin as the basis for your application, then the way I see it most of eclipse isn't really that necessary.

I am not certain I like how the SWT looks, or how responsive (or otherwise) it is. Swing is out of the question because I am going to use openGL. QT is my absolute top pick, but then I have to design the application framework myself.

The question is it worth it to spend serious time learning the eclipse application development foundation *and* figuring out how to get it working in a live coding sense, or should I just mess with QT?

It really bothers me, more than I would like. I have built applications before; the framework (the command architecture, input handling, the UI sub-structure) is really pretty detailed and takes a bit of effort. If you want chording inputs like emacs then you have to do a lot more work but that is honestly the only thing that makes sense. Now you want internationalization? That will take a bunch more work, something else eclipse has already solved well.

On the other hand, if you want great user-interaction; arguably eclipse does not have this solved. I don't like using eclipse; I always get into weird states with it and it really is slow. I would take visual studio over anything in most cases, followed closely by vim or emacs. Eclipse is a distant, distant choice I would only use if it really made sense. Perhaps this is ignorance on my part; but it is never enjoyable for me learning a new, large, non-trivial IDE. Visual studio crashes like it was born to but it is still pretty quick to do things with.

Actually, thinking about it I guess I could try to write some clojure extensions for eclipse before I jump into doing things with QT. The problem is that the UI lib is only 10% of the problem space that I don't care about any more. Everything else I mentioned is also a part of the space I don't want to solve in some amateur, one-off fashion.

But this is the thing. I am not going to use a system that doesn't support live coding. This means either I can launch it from the repl and come back to the repl by pushing a button (thus exiting the application's even handling) *or* I need some repl abilities *in* the app itself.

If I went with QT, I could run everything from the emacs-slime repl. If I go with eclipse, I will need to first build and extension that works with the repl.

Following my heart at this point means QT. Following my head means eclipse.

I guess that answers the question. I will mess with QT and hopefully come up with stuff that could be moved to eclipse should the need arise.

Clojure on mac osx

1. Download java 6
--EDITOR Do not do this if you want qtJambi to work on MacOSX.
--This is because there are only 64 bit java 6 implementations for OS X, and
--Trolltech have not released 64 bit compatible libraries *yet* for OS X. They don't appear
--to be all the close at the moment, either.
--You need to use 1.5.0, which is probably installed by default *if* you are using 10.5.
--EDITOR

go to here and link the current and currentsdk to 1.6.0
/System/Library/Frameworks/JavaVM.framework/Versions/

2. Set up aquamacs with slime:

http://groups.google.com/group/clojure/msg/ecbf7f87343d7f3f

Make sure to get both swank-clojure and clojure-mode from joshu's git repository

Be prepared to update the four of: clojure, swank-clojure, clojure-contrib, and slime so be sure you are get subversion/git/svn versions and can easily go into a directory and get fresh ones.

Yay! I have slime and clojure up and running!

That really wasn't very hard, now I can mess around with clojure a bit and try some things out. It is sweet, open up emacs and press f5 and there you go! I saw some errors flash by at one point but right now I don't care, the repl appears to be working (along with tab-completion of function calls).

Except now I have to remember all the emacs tricks that I have converted to vim tricks and forgotten about...

Why are emacs key bindings so crazy?

Tuesday, December 9, 2008

What is Eclipse?

When you think of Eclipse (I will refer to it as eclipse) you probably think of a large, corporate java editing platform. This is what it has become but it isn't what it is at its heart.

The core piece of eclipse is a plugin framework. This is the extent of my eclipse knowledge.

Given nothing else, eclipse is a system for managing plugins. Plugins can publish interfaces and 'extension points' (whatever that is) and they can state what interfaces they require for correct operation. They do this in an xml file, so Eclipse can delay-load everything based on a large plugin xml database.

The end goal of this project is to enable a live-coding environment in eclipse that is editing the eclipse application it is running in. I will attempt to do this using clojure but I don't actually know how possible this really is. It should be possible and if I am successful it would be a darn cool way to specialize the editing platform.

First off, I want to really understand what eclipse is. What datastructures are involved and how do you talk to them. I will want to understand what eclipse needs for various types of plugins and I will attempt to ascertain how amenable the system is to live-updating while it is running.

All I really need to do is figure out how I can build an eclipse plugin in clojure, however. There is a clojure plugin for eclipse already that is written in java but I will be god damned before I spend my free time working in java. I did that once and it took months of studying pure math for me to undo the dumness. I was awash in waves of dumnity and I almost drownded.

I am just going to study things like I usually do and update this blog as I study.   I am currently downloading the eclipse framework.  I already downloaded clojure and have no idea how to do anything with it but the repl.  Perhaps I can extend eclipse using the repl?  Is there (load-file "blah") functionality?  REPLs are nice, but typing things once is nicer.


Gotta start somewhere....

Opening the eclipse I was downloading. It is missing the "What the fuck are you?" button.

Reading the manual about the workspace, it appears that there is a small runtime kernel and a workspace on top of that. Where is the definition of the runtime component?

One thing going through my mind is 1. how ugly the interface is and 2. how slow it is to update. This isn't ideal; there really shouldn't be noticeable time between moving a window and seeing it change. I have been worried about this before and thus using the eclipse plugin framework with the QT UI framework definitely has come to mind.

Another thing I don't like about eclipse as it stands as it has moved some substantial project management functionality into its UI. These things seem orthogonal concepts to me...

perhaps a little closer:
http://www.eclipse.org/equinox/

Downloaded the osgi specification. I know this is overkill but I gotta. I hate it when you have to register for things to get them btw. It is a fucking spec, it is in everyone's interest for it to become common knowledge...

--"This aspect of the
Framework makes an installed bundle extensible after deployment: new
bundles can be installed for added features or existing bundles can be modi-
fied and updated without requiring the system to be restarted--"

This would seem to be the key enabler for a live-coding environment...

OK, reading a bunch about this stuff is interesting and I guess now it is time to start taking a bunch of other steps.

Overall, the OSGi system is an entire execution environment. Whereas when you compile a basic java program you get access to all of the java libraries you have referenced from your jar file, an OSGi bundle has access to libraries that it has declared it needed through a set of constraints.

So the classloader is specialized depending on your bundle specification and the existence of other bundles in the system. The environment takes care of things like loading two different versions of the same object, unloading and reloading shit and various other details.

What I was thinking was a lot lower level. If I implement stuff in clojure such that any interface I give to eclipse has a pointer to an implementation then I could conceivably just update the implementation pointer when I load the new file. Assuming I can find the interface I handed back to eclipse but I would assume in a forever-running runtime this should be possible. This would work regardless of OSGi nonsense, but at least there is one less term I have to filter out due to lack of information.

Next up I get some basic clojure editing working with my aquamacs emacs system. I got stuck earlier on classpath issues, but I need to read a lot more clojure editing environment tutorials. I am not certain what classpath means on a mac but I couldn't find a classpath environment variable....

Chris

Monday, December 1, 2008

Welcome to the club

I just paid another fee into the club of total pwnage. For those of you who don't live on computers, that means that I just got the receiving end of some shit. I had a part in that shit and it was wonderful but now things are all going lots of different ways.

As a lot of stories go, this one involves two women and one man. Their names and identities are withheld to protected the condemned.

One was an ex-gf, and one was a friend of the ex. There was some sleepin', seducin', and general debauchery goin' on, among things not fit to mention.

Needless to say, it all came crashing down hard with the man a victim of his own desire (first time for everything, hah!), and the women both victims of their own petty rivalries. Mutually assured destruction created mutual destruction.

There is a certain poetry to doing something really really dumb. Among that, ideally a certain amount of pain.

The whole situation just seems pretty contrived, really. I might also mention that the ex spent the night at the new boyfriend's house. And yet she was so angry about things in the morning.

The guy was seduced. A beautiful woman shows up at 12:30 at night at the house and what? You think the guy, who is not dating anyone, is going to just chill? Seduction rocks! Yay!

If anyone wants to try seducing me, btw, please, don't hold back. Furthermore, don't be surprised by the consequences.