Context free art - sort of

265 views
Skip to first unread message

Messinides, Mike

unread,
Feb 6, 2008, 7:18:46 PM2/6/08
to clo...@googlegroups.com

I found context free art a few weeks ago (http://contextfreeart.org/ ) and thought implementing something similar in clojure would be an interesting exercise (this isn't a port - I didn't look at the context-free code). My attempt is attached. There are two java classes included in the zip file that must be on your classpath, then load-file "cfa.clj" should bring up a frame with an example graphic. There are other examples commented out in the file as well.

This software is in the public domain.

Comments on the code are welcome.

<<clj-cfa.zip>>

clj-cfa.zip

Rich Hickey

unread,
Feb 7, 2008, 4:47:09 PM2/7/08
to clo...@googlegroups.com
On Feb 6, 2008 7:18 PM, Messinides, Mike <Michael.M...@invista.com> wrote:

I found context free art a few weeks ago (http://contextfreeart.org/ ) and thought implementing something similar in clojure would be an interesting exercise (this isn't a port - I didn't look at the context-free code). My attempt is attached. There are two java classes included in the zip file that must be on your classpath, then load-file "cfa.clj" should bring up a frame with an example graphic. There are other examples commented out in the file as well.


Very neat! I've attached a version that works with the latest SVN. I neede to add declarations for *gprob* and *gfn*, and swapped = for eql?
 

Comments on the code are welcome.


A couple of things:

Indentation matters - that's how Lispers read code. I re-indented the attached version.

Trailing parens on their own lines are not idiomatic.

The repeated 'def'ing of things not at top-level is a sure sign something's amiss - most likely you're using top-level vars as globals. I see you use refs when you know there will be multiple threads - they are a good idea whenever you are changing state.

(if (:x pmap) (:x pmap) 800) ==> (or (:x pmap) 800)

I might be able to help you with the defs once I understand the logic better.


But overall - bravo! You've created a graphics mini-language in ~300 lines.

The images are fun and all worked on my machine (OS X, JDK 1.5)

Thanks for the contribution!

Rich

cfa.clj.zip

MikeM

unread,
Feb 7, 2008, 8:07:47 PM2/7/08
to Clojure
Thanks for the fixes and suggestions. I realized today the code I
posted wouldn't work when I attempted to load it in a fresh REPL. I
deleted the defs for *gprob* and *gfn* from the cfa.clj file and since
my REPL had these already defined, it didn't balk when I reloaded the
file.

>The repeated 'def'ing of things not at top-level is a sure sign something's
>amiss - most likely you're using top-level vars as globals.

Yes, I am using top-level vars as globals. Is this bad style? This
seemed to be the easiest approach as I was incrementally developing
the functions and macros. Seems like namespaces would eliminate
problems with my globals conflicting with others.

Rich Hickey

unread,
Feb 7, 2008, 8:27:56 PM2/7/08
to Clojure


On Feb 7, 8:07 pm, MikeM <michael.messini...@invista.com> wrote:
> >The repeated 'def'ing of things not at top-level is a sure sign something's
> >amiss - most likely you're using top-level vars as globals.
>
> Yes, I am using top-level vars as globals. Is this bad style? This
> seemed to be the easiest approach as I was incrementally developing
> the functions and macros. Seems like namespaces would eliminate
> problems with my globals conflicting with others.

One of the ideas behind Clojure is that, if you use its constructs,
you will get a program that will work in the context of multiple
threads without incident.

The only reason Clojure allows vars to be re-def-ed is so you can fix
bugs in running programs.

What I've seen over and over in my career is code/data written under
the presumption that it wouldn't ever be used from multiple threads
eventually needing to, leading to much grief. So why not always do the
right thing, then if you eventually have multiple threads there will
be no problems. By using refs and/or agents, or thread-local var
bindings, you develop habits of state management that will serve all
of your Clojure programs well.

An uncontested ref is relatively cheap, I don't see any reason not to
use one.

So the short answer is yes, re-def-ing vars is bad style. I recommend
putting mutable state in a ref, agent, or thread-local var binding.

Rich

Jon

unread,
Feb 12, 2008, 3:37:32 AM2/12/08
to Clojure


On Feb 7, 10:47 pm, "Rich Hickey" <richhic...@gmail.com> wrote:
> On Feb 6, 2008 7:18 PM, Messinides, Mike <Michael.Messini...@invista.com>
> wrote:
>
> >  I found context free art a few weeks ago (*http://contextfreeart.org/*<http://contextfreeart.org/>) and thought implementing something similar in clojure would be an
> > interesting exercise (this isn't a port - I didn't look at the context-free
> > code). My attempt is attached. There are two java classes included in the
> > zip file that must be on your classpath, then load-file "cfa.clj" should
> > bring up a frame with an example graphic. There are other examples commented
> > out in the file as well.
>
> Very neat! I've attached a version that works with the latest SVN. I neede
> to add declarations for *gprob* and *gfn*, and swapped = for eql?

I wanted to try this cfa.clj, but I only had clojure_20080106, so it
didn't work. (I got "Unable to resolve symbol: = in this context".)
When will the next Clojure version be released? From the Clojure pages
I couldn't find any directions for how to obtain an SVN version.

Something else:
On the getting_started.html page, under "Quick Start", there's this
line: "In the directory in which you expanded clojure.zip, run:". I
think this should have been changed to: "In the directory you got when
you expanded clojure.zip, run:".

/Jon

arsala...@gmail.com

unread,
Feb 12, 2008, 6:43:28 AM2/12/08
to Clojure
On Feb 12, 1:37 pm, Jon <jon.klei...@usit.uio.no> wrote:
> I wanted to try this cfa.clj, but I only had clojure_20080106, so it
> didn't work. (I got "Unable to resolve symbol: = in this context".)
> When will the next Clojure version be released? From the Clojure pages
> I couldn't find any directions for how to obtain an SVN version.

Go here for those:

http://sourceforge.net/svn/?group_id=137961

--Arsalan

Jon

unread,
Feb 15, 2008, 8:45:22 AM2/15/08
to Clojure
Thanks for pointing me to the SVN stuff. I managed to build the SVN
Clojure verion. Now I've downloaded clojure_20080213, but I still
haven't succeeded in running the cfa.clj. I have put the cljext folder
into the clojure_20080213 folder, but when I do this ...

java -cp clojure.jar clojure.lang.Repl /some-path/clj-cfa/cfa.clj

... I get this:

Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad
version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
...

Am I doing something wrong?

/Jon

On Feb 12, 12:43 pm, "arsalan.za...@gmail.com"

Rich Hickey

unread,
Feb 15, 2008, 9:00:51 AM2/15/08
to Clojure


On Feb 15, 8:45 am, Jon <jon.klei...@usit.uio.no> wrote:
> Thanks for pointing me to the SVN stuff. I managed to build the SVN
> Clojure verion. Now I've downloaded clojure_20080213, but I still
> haven't succeeded in running the cfa.clj. I have put the cljext folder
> into the clojure_20080213 folder, but when I do this ...
>
> java -cp clojure.jar clojure.lang.Repl /some-path/clj-cfa/cfa.clj
>
> ... I get this:
>
> Exception in thread "main" java.lang.UnsupportedClassVersionError: Bad
> version number in .class file
> at java.lang.ClassLoader.defineClass1(Native Method)
> at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
> at
> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
> ...
>
> Am I doing something wrong?

cfa has a couple of small Java helper classes. It comes with their
source. You should build them yourself and include them on the
classpath.

Rich

Jon

unread,
Feb 15, 2008, 9:46:36 AM2/15/08
to Clojure
I guess you're talking about IPainter.class and DelegatingPanel.class.
Why I should have to build them myself, I don't know, but after a
couple of tries I had a new set of class files, and they work! I got a
window with some red-black vegetation. ;-) But redrawing the artwork
takes quite some time. Why is it so slow? (I use your modified version
of the cfa.clj.) Thanks anyway.

/Jon

MikeM

unread,
Feb 15, 2008, 10:59:26 AM2/15/08
to Clojure
> But redrawing the artwork
> takes quite some time. Why is it so slow? (I use your modified version
> of the cfa.clj.) Thanks anyway.
>

It's slow on my machine as well. I haven't made any attempt to
optimize, but I have some ideas to try and I'll post a new version if
I make any progress.
Reply all
Reply to author
Forward
0 new messages