Tuesday, August 28, 2007

DocPrinter package added to Verdantium -- 0828 ; Printing

This has been a busy week. I completed the century (100 mile) bicycle ride in the Tour De Cure in Longmont, Colorado on Sunday. It's a charity event to support Diabetes research. At the same time, I also got Tour De France winner Greg LeMond's autograph (yeah!). Coding this week has been delayed by all of the fun.

One of the visions that I've had for Verdantium is to make it a system for high-quality and resolution-independent printing. I've always wanted Verdantium to provide better printing APIs than those provided by Java Beans. The Java Beans framework primarily has the component (the bean) print on a single page by overriding the print() method of the java.awt.Component class. Java provides an AWT Printable interface with multi-page printing capability, but strangely Java Beans does nothing to detect or utilize a bean that implements the interface.

Verdantium provides direct support for a variety of printable components and printing scenarios. In the simplest case, a component may be embedded in the one doing the printing (e.g. a picture component in a word processing document). In this case, the typical print() method in java.awt.Component will be used.

If the component being printed is the top-level embedding component of the print job, then the following steps will be performed:

* First, Verdantium will determine if the callee implements the Verdantium BookPrintable interface. If this is the case, then BookPrintable will be used. BookPrintable is the most versatile interface, but is probably too heavyweight for most components.

* Second, if the component does not implement BookPrintable, Verdantium will determine if the callee implements the AWT Printable interface. If so, then Verdantium will work through the Printable methods, and potentially print on multiple pages. Most components that print on multiple pages will probably utilize this option.

* Third, if neither Printable nor BookPrintable are implemented by the callee, then Verdantium will use the print() method on the component's GUI.


For the typical multi-page component implementing Printable, Verdantium will automatically generate Print Preview windows, show Page Setup dialogs, work with the Swing RepaintManager, etc. Ditto for simple single-page components that don't implement Printable. BookPrintable is only useful of one wants to implements one's own PrintPreview GUI and/or one finds design issues having the Verdantium component directly implement Printable (i.e. sometimes it makes more sense for the Printable to be a separate class).


I think the support for Printable and BookPrintable makes Verdantium's printing significantly different from that in Java Beans, and creates possibilities for document automation (i.e. automated printing) that aren't possible in the Beans framework. To demonstrate this, I added a new component package called DocPrinter to the Verdantium project on Sourceforge. DocPrinter is a simple component that prints other components through a common interface. This includes components that print on multiple pages.

During the testing of DocPrinter I also noticed a series of Verdantium bugs that were created by some of the new multi-level undo improvements. Hence I posted a new Verdantium version, 0828, on Sourceforge that closes some issues that had to be fixed in order to make DocPrinter work with certain documents.

Like the EventViewer component posted earlier, DocPrinter is best used by first launching Verdantium ProgramDirector, and then loading DocPrinter's .xnl file through the Discovery component.

All of the Verdantium's printing frameworks use the Java Foundation Classes (JFC) Java-2D APIs. Java-2D uses resolution-independent coordinates, and should be able to take advantage of any high resolution (i.e. 300 DPI and above) printer. The specification for Java-2D was written by the same company (Adobe) that created PostScript, Display PostScript, and Adobe Illustrator. There are two issues to keep in mind with Java-2D. First, Java-2D can display characters with completely different font metrics depending on whether anti-aliased rendering is utilized. Second, Java-2D has been equivocal about the pixelation limits of its rendering.

Pixelation limits have dogged high-resolution rendering for decades-- long before Java existed. The original Mac used 16 bit pixel coordinates that extended from -32K to +32K. Different implementations of Win32 APIs have had different pixelation limits. If my recollection serves, Win95 had 16-bit pixel coordinates, whereas Win NT 4.0 had 32-bit coordinates. Different versions of Java-2D have had different coordinates sizes. On Windows, Sun JDK 1.2.2 and JDK 1.3 had coordinates that extended completely across the floating-point space. This later got truncated by Sun to smaller coordinates. Then Sun accepted a bug number to bring the larger coordinates back. If trying to make something work on multiple platforms and multiple JDK versions than one should probably assume truncated coordinates.

Nevertheless, Java-2D is a very sophisticated API and Verdantium takes full advantage of it. It should be possible to build some very powerful printing capabilities using Verdantium and Java-2D.

Thursday, August 23, 2007

Added EventViewer package to Verdantium

Posted EventViewer, a component that acts as a debugging tool for watching event traffic moving through the Verdantium system.

To use EventViewer, one probably wants to load it into an existing system through the Verdantium Discovery component. Discovery allows one to discover Verdantium components over the network in a manner similar to how network printers are discovered in most modern operating systems.

Unlike Sun's older Applet concept, discovered components don't have a security model. One needs to make sure to only discover components from trusted sources (probably from within one's own network). However, the lack of a security model is very advantageous. A discovered component has full access to the computer on which it is running, and this makes life a lot easier. Want to write to a file? Just select "Save." Want to print? Just select "Print." You get the idea.

The procedure for loading EventViewer through Discovery is as follows:

* Drop EventViewer.jar and EventViewer_14.xnl into the same directory.

* Launch the verdantium.ProgramDirector class from Verdantium.

* Click the "Run..." button, select the "New" tab from the resulting editor, select the "Discovery" component from the "New" tab list, and then click the "Apply" button.

* The Discovery component will launch in a separate window. Click the "Choose File" button, and then navigate and select the "EventViewer_14.xnl" file from the file chooser. The "Event Viewer" listing will then be added to the bottom of the list of components under the Program Director's "New" tab.

* Select the newly added "Event Viewer" item under the Program Director's "New" tab, and click the "Apply" button. The Event Viewer will be launched. Subsequent Program Director actions will be shown in the Event Viewer.


Using the URL option of the Discovery component, this same procedure works over HTTP. This makes it possible to dynamically load Verdantium components over the network. Try it.

Wednesday, August 22, 2007

New Verdantium Version -- 0822

This version is closer to Sun's standard naming conventions for the Java programming language, e.g. constants in all-caps. A lot of the changes are focused on the Meta project. There's a reason why Meta hasn't followed typical Java conventions: Meta is older than the Java language. It originally existed in C++, and was ported to Java circa JDK 1.0. It has undergone several changes since then. Parts the original Meta were dropped because they were obviated by the Java instanceof operator, other parts were later dropped because they were obviated by Java Collections Framework (JCF), classes were later added to handle XML encoding/decoding, etc. I've also added more Java exception support.

Several parts of the original Meta still haven't been obviated by the Java language. For instance, the FlexString class is still very useful. FlexString was originally a response to severe performance issues encountered with strings in C and C++. Adding a character to the start of a large C or C++ string requires pushing the entire existing contents of the string one character to the right. With Java, string performance is even worse. Adding a character to any part of a Java string causes a completely new string to be allocated, which copies the entire original string. FlexString is modeled after the standard pattern in simple text editors-- multiple text buffers with a mid-section gap between them. Changing the gap position allows characters to be efficiently inserted into any position of a large string. I find it amazing that a mainstream programming language hasn't added something like this to its standard libraries.

I think Meta is approaching a mature state. It will probably change in the future to accomodate generics, but I don't see any other major changes coming.

The new Meta caused basically everything to change: JUndo, JUndo Runtime, Umeta, and Verdantium. One needs the latest of everything to build.

There's more for me to do, but I wanted to get the changes to Meta done before the baseline grows too large. More on this later. I'm tired.

Saturday, August 18, 2007

New Verdantium Version -- 0818 ; Book "Beyond Java"

I think I now have a fully working (except for bugs) version of undoable verdantium.standard.DrawApp. All of the persistence code is in now. I have done some smoke tests on the persistence, and it seems to work. This should be the full implementation.

In addition to Verdantium, one also needs the latest versions of Meta and the JUndo Runtime for this to build and work.

All I need to do with this now is fix bugs, documentation quirks (e.g. lack of copyright headers), and other small issues. I also might want to make some of the code more elegant, but that's an issue for later.

On a completely separate note, I purchased an interesting book this morning: "Beyond Java" by Bruce A. Tate (O'Reilly). On one hand, I applaud this book for raising the question of what is beyond Java. I think there are issues that Java and C# don't address. I had to write JUndo in order to address some of these issues. However, I am completely perplexed by how the author selected which languages were important, and which languages were not important. The book considers Python, Ruby, Groovy, and .NET (mostly C#) as major contenders for next generation languages. AspectJ only gets ONE SENTENCE in the entire book. The author doesn't even consider whether the next major programming language might be aspect-oriented. AspectJ deserved much more than one sentence of mention from this book.

I think Java has a few more years in it, particularly since many Java developers haven't even upgraded to JDK 1.5 and generics yet. Nevertheless, the time has come to think about what's next after Java and OOP. The idea for the book was great, but the book's implementation of that idea left me wanting more. One can find several projects on either Wikipedia or Sourceforge that seem significant, but get no mention in the book. For instance the language Pizza was never widely adopted, but was tremendously successful in demonstrating how generics could be added to the Java language. JDK 1.5's generics probably owe something to the Pizza language. Languages that never get wide adoption can be very important in defining the future of programming, and I wish this book would have included many more obscure languages.

Tuesday, August 14, 2007

JUndo-- Beyond Java with Undo

This is the text of a presentation on JUndo that I gave to Pikes Peak Java Development Group (PPJDG) on Sept. 26, 2006. This was apparently the last meeting that PPJDG had. The group is now defunct. There has been no traffic on its mailing list for the last year, as shown here:


http://groups.yahoo.com/group/ppjdg/



Regardless, I think this provides a good overview of the language for those who don't want to read through long technical descriptions. Note: I've improved the implementation since I gave this presentation, so some of the "to-do" items no longer apply.




Presentation


Object-Oriented Programming (OOP)

Aspect-Oriented Programming (AOP)

Time-Oriented Programming (TOP)

This is a TOP presentation.




History


Conceived at Arizona State University circa 1998.

Major Inspirations: Prof. Edward Ashcroft, Prof. Tony Faustini

First cut of compiler tested in mid-1999.




Background


Verdantium Compound Document Framework

Distribute Small Components (Desktop Apps) Over Network

Many components need multi-level undo support in order to be viable




Motivation


Having each component implement its own undo framework causes each component to be large

Hence the need for a common framework

Framework must be general enough to encompass all components




Problems


Object Creation

Changing object members and object-object references

Objects becoming unreachable / garbage collection

Decisions (i.e. if-then)



More Problems


Scripting

Nested Operations

Error Recovery




Possible Solutions


Create A “Reverse Command” for every command (u/ by Swing).

For Instance, the reverse of “insert character” is “delete character”.

But... (see next page)




Example


int value;


public void dumbCommand()
{
if( value > 100 )
{ value = 5; } else { value = 6; }
}




Possible Solutions


Save a Memento of the data state before running command.

Comes from Design Patterns book.

Prohibitively Expensive To Save Everything.



Possible Solutions



For each member use a class with an overloaded assignment operator. Store values.

Override equiv. of malloc() and free().

Hard to implement other than C++ (e.g. Java).




Undo


General undo requires tracking all object creation, deletion, and member assignment.

This changes the semantics of the original language, and perhaps is better handled at the language level.




JUndo


JUndo is intended to provide a semantics that simplifies undo and error handing.

But it’s more than just Java with Undo...




JUndo Example



public class IntRef
{
private int val;

public int getVal( )
{ val };

public milieu setVal( int invb )
{ val := invb };

}




Operators



In JUndo there are no statements. Everything in a method body is an expression.

“:=” is a function that takes in a milieu and a value, and returns a milieu.




Currying



In C++ the “this” pointer is curried into each instance method. The JVM uses a similar technique.

In JUndo a “this-milieu” reference is curried into each method.

Jundo also provides a “now” keyword.




Pairs



Consider the next() method on a Java Iterator. Often this method both alters the iterator’s members and it returns an object.

This kind of update-and-return method is so pervasive that JUndo has a special type called the pair to handle it.




Example



public class IntRef
{
private int val;

public int getVal( )
{ val };

public milieu setVal( int invb )
{ val := invb };

public static pair[ IntRef ] new_IntRef( int in )
{
let
{
pair[ IntRef ] ref = IntRef.allocate_IntRef();
milieu asgm = ref.setVal( in );
}
with [ ref.cobj , asgm ] fi
};

}



Example



pair[ IntRef ] ap = IntRef.new_IntRef( 3 );

IntRef a = ap.cobj;
milieu t0 = ap.milieu;

milieu t1 = [ a , t0 ].setVal( 7 );

milieu t2 = [ a , t1 ].setVal( 4 );

/* ********************************************** */

int a0 = [ a , t0 ].getVal();
int a1 = [ a , t1 ].getVal();
int a2 = [ a , t2 ].getVal();

a0 is always 3.
a1 is always 7.
a2 is always 4.




If-Then Expr.


Like everything else in JUndo, if-then is an expression rather than a statement.

The expression can return any type, including milieu and pair.

if x > 5 then 25 else 36 fi

Switch is similar.





Garbage Collection



In Java, an object can be collected when it is no longer reachable.

In JUndo, an object can be collected when it is no longer reachable from any object in any milieu.

A milieu can be collected when it is no longer reachable from any object in any milieu.



Iteration



In Java, programs are primarily constructed using loops (e.g. while loops).

In intensional languages (e.g. Lucid) recursive definitions x = 5 fby prev( x )+3.

JUndo uses selections inspired by TRC.




Iteration



public interface Iterator
{
public pair[ boolean ] hasNext();
public pair[ Object ] next();
}



public interface IteratorFactory
{
public pair[ Iterator ] iterator();
}




Example



public class TestClassB
{

public static pair[ IteratorFactory ] calc( IteratorFactory fac )
{
seq now into
{
pair[ IteratorFactory ] res = select a from a : fac where
[ seq now into
{
IntRef r = ( [ IntRef ]( [ a , now ] ) ).cobj;
}
with ( r.getVal() > 10 ) fi ]
fi;
}
with res fi
};



Example



public class TestClassA
{

public static milieu calc( IteratorFactory fac )
{
seq now into
{
IteratorFactory res = ( select
[ seq now into
{
IntRef r = ( [IntRef]( [ a , now ] ) ).cobj;
r.setVal( 5 );
}
with now fi ]
from a : fac where true fi ).cobj;
Iterator it = ( res.iterator() ).cobj;
IteratorUtils.getLastItem( it );
}
with now fi
};




Example



int calc()
{
int total = 0;
int i;
int j;
for( i = 0 ; i < 10 ; i++ )
{
for( j = 0 ; j < 10 ; j++ )
{
total += i + j;
}
}
return( total );
}



public static int calc( )
{
seq now into
{
IteratorFactory af = ( ForIntLe.new_ForIntLe( 0 , 10 , 1 ) ).cobj;
IteratorFactory bf = ( ForIntLe.new_ForIntLe( 0 , 10 , 1 ) ).cobj;
IntRef total = ( IntRef.new_IntRef( 0 ) ).cobj;
IteratorFactory res = ( select
total.setVal( [ { [ForIntLeIterator]( [ a , now ] ) }.getValue() ] +
[ { [ForIntLeIterator]( [ b , now ] ) }.getValue() ] +
[ total.getVal() ] )
from total ; a : af , b : bf where true fi ).cobj;
Iterator it = ( res.iterator() ).cobj;
IteratorUtils.getLastItem( it );
}
with total.getVal() fi
};




Referential Transparency



Function returns the same thing when given the same params, i.e. f(10).

Many critical functions in C, e.g. malloc, violate this.

Like C, JUndo allocates. But the language is contrived to preserve referential transparency




Transparency



Transparency presumes that “this” and “thismilieu” are counted as parameters.

Comparison operators not supported for milieux.

Some safety is traded to get both transparency and performance.




Safety



Like C++ and C#, JUndo trades away some safety.

Comparisons should only be used on objects in the same milieu. For objects from different milieux, results are undefined but transparent.

Don’t try to access an object in a milieu where it doesn’t exist. The result is undefined.




So What Is This Good For?




It’s difficult to just “add” undo to an existing program.

JUndo started as an investigation of the feasibility of adding undo capability to Java software developed for the Arizona State University department of Physics.

there are potential applications for scripting, error control, and formal definition of algorithms.

In addition to simple classes, JUndo also has undoable maps.




Undo Mgmt.



class UndoNode
{
UndoNode nxt;
MilieuRef state;
}

class UndoImpl
{
UndoNode undoStk;
UndoNode redoState;
UndoNode currentState; /* nxt always null in currentState */

public MilieuRef getCurrentMilieu()
{ currentState.state };

public milieu commitStateAction( MilieuRef newState )
{
seq now into
{
UndoNode node = currentState;
node.nxt := undoStk;
pair[ UndoNode ] newPair = [ UndoNode , now ].allocate_UndoNode();
UndoNode newNode = newPair.cobj;
newNode.state := newState;
currentState := newNode;
redoState := null;
}
with now fi
};





Undo Mgmt.



public milieu performUndo()
{
if undoStk != null then
performUndoComp() else now fi
};

protected milieu performUndoComp()
{
seq now into
{
currentState.nxt := redoState;
redoState := currentState;
currentState := undoStk;
undoStk := undoStk.nxt;
currentState.nxt := null;
}
with now fi
};



Undo Mgmt.





public milieu performRedo()
{
if redoState != null then
performRedoComp() else now fi
};

protected milieu performRedoComp()
{
seq now into
{
pair[ UndoNode ] nodep = [ currentState , now ];
UndoNode node = nodep.cobj;
node.nxt := undoStk;
undoStk := node;
currentState := redoState;
redoState := redoState.nxt;
}
with now fi
};




Example-JUndo



class BorderModel
{
protected jobj borderClass;
protected jobj borderTypes;
protected jobj borderParam;

public jobj getBorderClass( )
{ borderClass };

public jobj getBorderTypes( )
{ borderTypes };

public jobj getBorderParam( )
{ borderParam };

public milieu setBorderObject (
jobj _borderClass ,
jobj _borderTypes ,
jobj _borderParam )
{
seq now into
{
borderClass := _borderClass;
borderTypes := _borderTypes;
borderParam := _borderParam;
}
with now fi
};

/* ... */




Example-Java




public String getClassName() {
Object obj = borderModel.pdxm_getBorderClass(undoMgr.getCurrentMil());
return ((String) obj);
}

public Class[] getBorderTypes() {
Object obj = borderModel.pdxm_getBorderTypes(undoMgr.getCurrentMil());
return ((Class[]) obj);
}

public Object[] getBorderParam() {
Object obj = borderModel.pdxm_getBorderParam(undoMgr.getCurrentMil());
return ((Object[]) obj);
}

public void setBorderObject(String CName, Class[] types, Object[] params)
throws ResourceNotFoundException {
ExtMilieuRef mil =
borderModel.pdxm_setBorderObject(
undoMgr.getCurrentMil(),
CName,
types,
params);

undoMgr.handleCommitTempChange(mil);
firePropertyChangeEvents();
}




Undo-Java



public Object processObjEtherEvent(EtherEvent in, Object refcon)
throws Throwable {

Object ret = EtherEvent.EVENT_NOT_HANDLED;

if (in instanceof PropertyEditEtherEvent) {
if (in.getEtherID().equals(PropertyEditEtherEvent.isBorderSupported))
return (PropertyEditEtherEvent.isBorderSupported);

if (in.getEtherID().equals(PropertyEditEtherEvent.setBorderObject)) {
Object[] myo = (Object[]) (in.getParameter());
UTag utag = new UTag();
undoMgr.prepareForTempCommit(utag);
setBorderObject(
(String) (myo[0]),
(Class[]) (myo[1]),
(Object[]) (myo[2]));
undoMgr.commitUndoableOp(utag, "Border Change");
return (null);
}
}

return (ret);
}




Other J-Lang


AspectJ.

Godiva (goal-directed evaluation).

Nice (ML, Haskell, and Eiffel).

Kiev (Prolog inspired)

Bistro (Smalltalk Inspired)

Scripting languages (BeanShell, Groovy)

JRuby (Ruby), Jython (Python)

Source: Wikipedia




To-Do


Improve garbage collection of JUndo objects

Exception Handling (try-catch)

JUndo linked lists (Vectors too)

Provide more coding examples / convert more components to use JUndo

Educate people

Fix remaining compiler bugs

Method Overloading




Questions?



http://verdantium.blogspot.com/

Monday, August 13, 2007

Object Models, Google, and Star Office

According to "The Haskell School of Expression" by Paul Hudak, "Java's recent astonishing rise in popularity is rather perplexing on one hand, yet quite understandable on another. As a language, it is simple and elegant, but certainly not revolutionary." The syntax of Java is similar to C and C++ and there are semantic similarities (hence Java's not revolutionary), but this does not explain why Java was successful or what should be done next.

C++ preceded Java, but C++ objects were basically C structures with added intelligence. Objects in the C++ runtime did not retain their identity. For instance, there was no way to introspect the objects generated by the early C++ compilers such as cfront.

Document object frameworks such as Apple's OpenDoc and Microsoft's Object Linking and Embedding (OLE) required objects with a built-in identity that could be dynamically linked. Objects for these frameworks needed to be separately compiled, and loaded at runtime. Microsoft solved this problem with the Microsoft Common Object Model (COM). Apple's OpenDoc used IBM's System Object Model (SOM), which was an implementation of the Common Object Request Broker Architecture (CORBA).

Typical CORBA development had the programmer produce Interface Definition Language (IDL) bindings to a standard language such as C or C++. This required the production of several entities such as IDL stubs, IDL skeletons, etc. Introspection in CORBA required the use of a Dynamic Invocation Interface (DII) in which dynamic requests were built through a long series of C-like API calls. The CORBA code then had to be submitted to an Object Request Broker (ORB). This made OpenDoc programming a labor-intensive process. Apple tried to solve this problem by creating a "Direct-To-SOM" compiler that would take C++ class definitions and compile them into CORBA objects.

Java appeared at the perfect time and it succeeded where Direct-To-SOM failed-- it provided a simple, straightforward language for building CORBA-like objects. The objects ran in a Virtual Machine (VM), but the VM acted much like an ORB. Later, Sun published a Introspection API for Java that made CORBA DII look like a cumbersome dinosaur.

Java quickly became the perfect language for writing an OpenDoc-like component model. An early pioneer in this realization was one of my former ASU professors: Tony Faustini. Faustini taught computer language courses at Arizona State, and two of his passions were visual languages and functional programming. When Sun announced Java and Applets to the world, Faustini immediately understood the implications. Very early in the history of the language, around the time when Sun was releasing Beta Applet APIs for the upcoming Java 1.0, he did something that I wouldn't fully appreciate until much later. He apparently found the Java ClassLoader APIs, and used them to build a container that loaded a series of visual components on startup. As it went through the loading process it displayed the loaded components in a progress bar-- much like the one Photoshop used when loading plugins on startup. The result was called Visual Java (not to be confused with the commercial product that is currently being called Visual Java). Visual Java could best be described as a GUI builder using an operator-net representation of the programming language Lucid, where the operator-net entities were dynamically loaded at runtime through a ClassLoader.

Through some promotional efforts by Faustini, Visual Java soon found its way to Sun Microsystems and Java evangelist Miko Matsumura. There is an early Java-related telecast with Miko Matsumura and Sun engineer John Gage where Miko used Visual Java to first make an animated dog run forward and then run backward. I developed a MacDraw-like component for Visual Java called Fresco. Verdantium was influenced by all of this.

To make a long story short, part of Visual Java wound up in Sun's BeanBox container for Java Beans. Part of Visual Java wound up in a Sun product called Java Studio. Java Studio seems very far removed from Tony's original vision. I don't know what, if anything, happened to Fresco. In a sense Visual Java turned into Java Beans, and then Java Beans integrated, after many travails, into systems like Star Office.

Suffice it to say I found it interesting when Google today announced it was going to start bundling Star Office with its products. I think Google is starting to understand reality-- they've realized that they aren't going to do everything with web applications and AJAX. I also have doubts about whether Star Office will be a success against Microsoft Office.

Microsoft Office is the McDonalds Happy Meal of the software industry. It is a single monolithic box packed with a hamburger (Microsoft Word), french fries (Microsoft PowerPoint), a soft drink (Microsoft Excel), and a toy (Microsoft Access). Microsoft produces lots of them with enormous economies of scale, and they're all pretty much the same. Star Office is trying to be the cheaper Happy Meal, or the more agile Happy Meal, or the more international Happy Meal, or the Happy Meal that is available in more places, etc. It's hard to imagine any of Star Office's marketing slogans really working, particularly if Microsoft tried to marginalize Star by cutting the price of MS Office. It's hard to make a big monolithic box better than Microsoft. Star seems to be trying to make something a lot like MS Office, and generally seems to be trying to beat Microsoft as its own game. As a strategy, this doesn't seem to be smart.

To compete with Microsoft, Google and Sun need to address the big truth that Microsoft ignores: most people don't want Happy Meals. As Simon Phipps stated during the 2007 JavaOne conference, people want to go to a buffet table where they are free to choose what suits their tastes. That is to say, the Java community needs to develop framework technologies that can be used to leverage the best talents of the Open Source community. Different people want different application suites. Ever notice how Adobe's application suite (i.e. Photoshop, Illustrator, etc.) looks very different from Microsoft's? Observe: Adobe doesn't even provide a spreadsheet. This shows the kinds of choices that people want from their "buffet table." Some people want Photoshop instead of Microsoft Paint (or vice versa). Some people want a page layout program instead of a word processor. Some people want Gantt charts built directly into the suite, and other people would rather not have to drag all of that code through their CPUs like a boat anchor.

Unlike the typical Microsoft offerings, Java is a language that can make the buffet table work. Tony Faustini demonstrated years ago how how to write code that can put the various items on the table at runtime. It's one of the main reasons why Java has been successful as a language. Choice is a fundamental human desire, and it's a desire that Microsoft doesn't satisfy. An open framework providing choice fully utilizes the best strengths of the Java programming language. Instead of another Happy Meal called Star Office with pre-configured applications, Google and Sun should be providing the full buffet table.

Sunday, August 12, 2007

New Verdantium Version 0812

This was another day in which I have been doing a lot more coding than blogging. As in previous days, I have been continuing to work on the new version of class verdantium.standard.DrawApp. Today I got some persistent writes to work from the new DrawApp. Haven't had a chance to test persistent reads yet.

The new Verdantium requires downloading a new JUndo Runtime (both the jundoruntime and umeta packages). Otherwise, the new persistent writes won't work at all.

I also uploaded a new version of the JUndo compiler. Very small changes here. Mostly I fixed some nebulous error message generation.

Saturday, August 11, 2007

New Verdantium Version-- 0811

This release has more work on the undoable version of verdantium.standard.DrawApp. I think all of the functionality is in place for undoable DrawApp except for the persistence support.

Now that I'm almost finished with an undoable drawing application, I've been thinking about producing an undoable text application to replace class verdantium.standard.TextApp and connecting to Sourceforge's Subversion capability. Use of Subversion would allow Verdantium source code to show up on Google Code Search. That would be a good thing.

I might also rewrite some of the change log descriptions in the JUndo and JUndo Runtime projects. Some of my recent uploads on these projects have proven more stable than I thought they would be, and I might rewrite the version logs to declare them to be stable baseline versions.

Anyway, I'm doing more coding than blogging today, so this is a short post. More later.

Thursday, August 9, 2007

Is AJAX really the next big thing?

I woke up this morning and realized to my surprise that it's been about ten years since Apple cancelled its ill-fated OpenDoc project. The cancellation of OpenDoc led directly to the creation of the first version of Verdantium, and ten years later I'm still not finished with it.

Ten years is a long time in the technology field. OpenDoc, even after all of this time, still seems ahead of its time. OpenDoc's concept of small cooperating visual components still does not seem to have been replicated by any popular mainstream framework. Nevertheless, I have thought about Verdantium's future. One one hand someone could argue that Verdantium is a really quaint JFC/Swing system that has been outmoded by the new shift toward Web Applications, Asynchronous Javascript and XML (AJAX) and Service Oriented Architecture (SOA). On the other hand, Verdantium's still seems to suggest a utopian future software architecture rather than a prosaic replay of the past.

There are some projects that the new AJAX web applications do well, and there are other projects that they don't seem to do well at all. Google Documents seems like the ultimate blog creation system rather than something that could overthrow office applications like Microsoft Word. The Google system ignores the printed page-- there's no page view, no print preview, no headers, no footers, no table of contents generation, no settings for different printer page sizes (e.g. A4), no color matching, no kerning, etc. Supporting all of this would require two things: first getting printer information to the network server, and second sending lots of bitmaps over the network in real-time. The second of these is likely to be prohibitive compared to Microsoft Word running in Page View. All of the bitmaps probably won't cross the network fast enough.

In spite of the hype about AJAX-based office applications running on a thin client, it's hard to imagine an AJAX-enabled word processor replacing current desktop software. And that's just the word processor. What about image processing? Would anybody want to use the equivalent of Photoshop over a network pipe?

I think the dominant productivity applications of the future are still going to run very thickly (as in thick-client or typical MS-style office application) on the CPU of the end-user's PC. But at the same time, I think it is possible to have a paradigm shift in how those applications are created.

In the currently dominant office applications Microsoft Office, Corel Ofice, Star Office, etc., there are a small number of enormous monolithic container applications (Microsoft Word, Microsoft PowerPoint, etc.) that embed smaller custom components (e.g. JPEG Movie Players) through protocols (e.g. Microsoft OLE/Active-X). This is counterproductive for both users and developers. Users can't mix and match components as they see fit. Developers don't have options for collaborating.

Imagine a framework where one could create a custom productivity suite by rolling together a large number of very small components through a protocol. No dominant office application-- just a protocol. That was what Apple originally proposed with OpenDoc, and even today it still seems like an exciting idea. Leverage each developer's particular skills. Have each developer write a small component in the domain she knows. Don't try to write a huge containing application, but instead provide a way for many smaller components to work together to create the equivalent of a powerful office suite.

Ever notice that it seems hard to write container applications in Microsoft OLE and Active-X? Of course it is. A lot of small, utilitarian container applications embedding each other could gang up on Microsoft Office.

In Verdantium, I tried to make it especially easy for developers to write container applications. In fact, anybody can write a container component supporting multi-level undo and scripting in a few hundred lines of code. In fact, there's a package in the Verdantium download on Sourceforge called MyContainerApp that gives a fully coded example of this. One who looks through the Verdantium source code long enough will find several other examples. I still think this is relevant post-AJAX.

The Verdantium undo system seems much more advanced than the other undo frameworks I've seen. It's more advanced (and faster) than trying to roll back a relational DB. It's more advanced than the system Sun has in the Swing APIs (which uses the inverse command pattern). It's more advanced than what Apple used to ship with OpenDoc. I am not aware of any Java-enabled open-source framework that is providing a temporal undo capability. I'm not aware of any web application frameworks for doing this, either. Temporal undo is highly advantageous for keeping the self-consistency of the multi-level undo implementation high while keeping the SLOC count (and hence the number of bugs) low. People like small, powerful components that are bug-free. Did I mention that multi-level undo is a capability that many Microsoft Office users ABSOLUTELY REQUIRE? That is to say, they will NEVER switch without it.

I think there is a point to all of this in the post-AJAX and post-SOA world. As computers get faster, there will be a point in the future where a Java-enabled system such as Verdantium will be "fast enough" compared to the current productivity suites. Verdantium will get there long before AJAX does (if AJAX gets there at all). Time is still available because technology hasn't yet advanced to make either alternative fast enough (yet!). "The future" could still happen.

Tuesday, August 7, 2007

A short description of JUndo

JUndo-- A Novel Declarative Language


This is the text of a journal paper that I once submitted to SIGPLAN. The paper was rejected on the argument that JUndo was too similar to Haskell. I don't recall Haskell supporting inheritance, polymorphism, or late binding... oh well.


Summary

Typical object-oriented languages such as C++, C#, and Java do not provide direct support for declarative programming. However, large object-oriented programs often integrate declarative concepts in order to implement requirements such as transaction rollback in complex object systems, multi-level undo in large applications, and sophisticated forms of error handling that are intended to return the software to an initial state after an exceptional condition is encountered. A novel language, JUndo (pronounced "jun-doh"), is presented here that allows manipulations of object-oriented data to be expressed in a declarative manner. Further, a set of objects containing an arbitrarily complex set of object-object references can be reverted to a previous state in a straightforward fashion using the language’s constructs. This can be very useful for returning an object system back to a previous consistent state after encountering an exceptional condition.

Key Words: object-oriented programming, functional languages, declarative languages, history management, undo, redo, JUndo

Introduction

This paper describes a language motivated by issues in the implementation of undo capabilities in complex object systems with typical languages (C, C++, Java). One possible undo implementation is to implement the Memento pattern from [9], and then save a Memento before executing each individual command. For many complex object systems this has prohibitive memory and/or performance costs. Another possibility is to use a Command pattern such that there is a "reverse" operation for each operation performed [9]. For instance, the "reverse" of changing the drawing color from blue to red is to change the same color back from red to blue. Edwards suggests that this approach often doesn't work in "real world" applications [8]. This is because the precise side-effects a command may generate can not be known a priori, and hence it is sometimes extremely difficult to compose a command that will reverse them. Edwards solved this problem in the Flatland system by breaking each user-generated command into a sequence of simpler "atomic" commands for which the undo operations could be expressed [8]. Performing undo on a Flatland user command involves invoking the undo operation for each of the simpler commands in the sequence. The author contends that even this approach will not scale for certain types of large systems. That is to say, there are certain types of systems for which it is non-trivial to create simpler "atomic" commands. Consider a command that parses an expression, evaluates the expression, and then side-effects the system by assigning the results of the expression into variables that are used to calculate the results of other expressions (using a topological sort to determine the order of expression evaluation). Generating simpler undoable commands for this requires opening the private internal data of the entire parsing, evaluation, and topological sort pipeline to the command processor so that the undoable commands can access all the individual data members. At best, this seems like a questionable idea from an architectural standpoint. It could also be extremely difficult to implement.

ACIS [6], a commercial solid modeler, provides an example of a undo implementation that does scale. ACIS defines its own base class, and its own pointer class with overloaded assignment operators. Whenever an object is created or deleted or a pointer is reassigned, a record of each change is stored by ACIS. The ACIS undo process essentially consists of reversing each stored object change in the proper order. The ACIS API represents undo information in the form of delta states, where a delta state is, in a very high-level sense, a pointer to a ordered set of undoable object changes. This implementation succeeds because it does not attempt to generate any a priori commands. Instead, the overloaded assignment /creation/destruction operators react to changes as they happen at the object-member level. Arbitrarily complex commands can be handled by such as system with no need to break them into simpler commands as done in Flatland [8]. Such an implementation is very complex, but it does work. The ACIS system is so complex that it borders on being its own programming language. The ACIS APIs were written in C++ using C++ operator overloading. The use of operator overloading to such an extent arguably changes the semantics of C++ objects. For instance, using the delete operator does not actually delete such an object. Instead, the discarded object is attached to a change list.

The JUndo Language

JUndo is motivated by the idea that the semantics of undoable objects, e.g. those created by the operator overload method, are better defined at the language level. That is to say, the language should provide high-level abstractions of the object system state that enable the programmer to focus on creating value-added algorithms rather than laboring on yet another undo implementation. Intensional languages such as ISWIM [1] define time streams that are in many aspects similar to the timelines in [8]. However the intensional time stream, like the delta state, defines streams of data rather than streams of commands. JUndo is not used to write programs. Instead, it generates undoable classes that are embedded in much larger programs such as Verdantium [10]. The rest of this paper will describe the language, to the fullest extent possible in the remaining space, using a set of small coding examples. In Java, a simple class with getters and setters is written as follows:


class IntRef
{
private int val;

public int getVal( )
{ return( val ); }

public void setVal( int inv )
{ val = inv; }
}


The JUndo equivalent of this class is as follows:


class IntRef
{
private int val;

public int getVal( )
{ val };

public milieu setVal( int inv )
{ val := inv };
}


First, JUndo method bodies are expressions rather than collections of statements. Second, note the presence of the keyword "milieu". This keyword, named by ASU professor Edward Ashcroft, defines an environment containing the state of a set of cross-liked objects. Third, the expression val := inv does not side-effect an object member in the usual sense. Instead, it is a functional operator that takes in a milieu and a value (in this case inv) and returns a milieu. The milieu input to operators such as := is curried into each method, much as the "this" reference is curried into each instance method.


JUndo allows multiple parenthesis-types in an expression (parenthesis, brace, or bracket), so the following is also valid:


class ExprnClass
{

public int getVal( int a , int b , int c , int d )
{ a * ( b % [ c - { d * d } ] ) };

}


The nesting of multiple levels of parentheses in other languages such as LISP and Scheme can be confusing. The use of multiple types of parentheses in JUndo is intended to help address this issue, and allow a syntax that is more similar to that or C++, Java, and C#.

there is no "return" statement in JUndo. Unlike methods in Java and member functions in C++, methods in JUndo can not have a "void" return type. In fact, there is no "void" keyword (and no equivalent) in the JUndo language. Methods in JUndo must return some non-void entity. This makes JUndo a totally declarative language in the sense that imperative semantics (i.e. statements that either directly alter or side-effect previously defined values) are never used. Instead, methods are defined that leave previously declared values unchanged. JUndo equivalents to methods or member functions with a "void" return type would most likely return "milieu" as in the sample code above.

In JUndo, a milieu is a primitive type just like an integer or a character. Milieux can be manipulated and stored in objects just like any other datatype. This is an important feature because it allows object systems to manipulate entire milieux of data within an application. This allows a set of instances to be pigeonholed into a single element that can be moved from structure to structure as necessary. There are a number of design advantages in being able to keep a closed system of objects as an independent element in a data structure. It makes that set of instances so that they can not be manipulated by another object unless that object has access to that particular milieu. This can be used to shield a set of objects from unauthorized access. It also allows for the creation of data structures of milieux, which is important for implementing concepts such as multilevel undo. An example of a simple class containing a milieu as an instance member is shown below:


class MilieuRef
{
private milieu val;

public milieu getVal( )
{ val };

public milieu setVal( milieu inv )
{ val := inv };

}


Pairs and Object Creation


Like the language Objective C, JUndo does not have constructors. Objects are constructed using class methods. This is advantageous for classes that are designed to only create objects in a selective fashion. For example, some classes are designed to only allocate a new object if an object of identical value does not already exist. A number of string implementations use this to ensure that two strings are identical iff. their OIDs are. This can greatly reduce the amount of computation time required for string comparison. Using a class method (as indicated by the static keyword) instead of a new operator gives each class direct control over when and how its instances are created. An example of a class method to create an object of class Singleton is:



class Singleton
{
protected static Singleton instance;

public static pair[ Singleton ] new_Singleton( )
{
if instance != null then [ instance , thismilieu ] else
let
{
pair[ Singleton ] sing = [ Singleton , thismilieu ].allocate_Singleton();
milieu q = [ Singleton , sing.milieu ].instance := ( sing.cobj );
}
with [ instance , q ] fi fi
};


/* More Code Here ... */


}


This example also introduces a new JUndo data type called the pair. The pair of a object reference of type A is defined as . Pairs do NOT have OIDs, and they do not exist in milieux except as members of objects or classes. One can see why the pair is useful by thinking about what the new method does. It both creates a new object, and it creates a modified milieu that contains that new object. The pair makes it easy to return both of these entities to the caller at the same time. A pair is built by placing the item and milieu that it is to contain in brackets in a manner like the following: [ obj , thismilieu ]. Elements can be extracted from a pair using the .cobj and .milieu operators. The construction class methods, which can be given arbitrary names, allocate new objects by using the protected class method allocate( provided by the runtime. After allocating the object, the method is then free to initialize it in arbitrary ways (as the above example does).

Because a pair always contains two and only two elements, the compilation of a pair takes on many of the characteristics of the compilation of a primitive type. An JUndo compiler treats pairs very differently from the manner in which a standard compiler would handle code generation for a typical derived type such as an array or a record. To review, expressions on a primitive type in typical languages are mapped to primitive operations (in a language like Three Address Code) that write to temporary variables defined by the compiler. Each primitive operation has one primitive temporary variable as its result. Similarly each primitive expression on an JUndo pair, in the compiled representation, has two temporary variables as its result: one for the object reference and one for the milieu. Moreover each primitive operation on a pair maps to two Three Address Code operations, one for each of the two temporary variables that make up the pair. In this way pairs get mapped directly to lines of Three Address Code in the same way that a primitive type does, except that everything with a pair gets mapped to two lines instead of one. This allows operations on pairs to mapped into more efficient code than is otherwise possible. This is an important optimization because pairs play a fundamental role in the language.

Inheritance, Encapsulation, and Polymorphism with Functional Programming


An object-oriented language can be defined as one that supports inheritance, encapsulation, and polymorphism. JUndo supports all of these concepts. JUndo's implementation of these concepts is almost identical to JDK 1.4 (except that JUndo doesn't support inner classes). Intensional languages often define functions by declaring them in let blocks. In contrast, JUndo doesn't support this. JUndo, following the Java convention, requires "functions" to be implemented as methods in the scope of some class. However, JUndo methods can call each other in the same recursive fashion as intentional functions. Methods are preferred over let-functions for a couple of reasons. First, methods can be translated into efficient object code more easily then let-functions. This is particularly true when writing code for a Java virtual machine. Second, methods can be overriden yielding a greater degree of expressive power. Finally, the use of methods is more consistent with the concepts of data abstraction.

JUndo contains a complete set of functionality for producing a functional program, but does not provide some of the operators from intensional programming such as “fby”, “prev”, “next”, and “at”. The semantics of these operators are such that their implementation tends to be recursive, although there are optimizations for mapping special cases such as tail-recursion to non-recursive code. A language does not necessarily need to be recursive in order to define its operations using a declarative semantics. For example, the Datalog programming language uses Domain Relational Calculus to map a number of Datalog rules into iterative relational queries. In Tuple Relational Calculus, an example of a declaration of a simple iterative (SQL-like) query expression is as follows:


select A.emp from A, B where [boolean expression]


Another trend in Object-Oriented programming is the use of iterators in frameworks such as Java Collections Framework (JFC). For instance, a Java method using iterators might resemble the following:



public Iterator getEmps( Iterator E , Supervisor S )
{
Vector v = new Vector();
while( E.hasNext() )
{
Employee emp = (Employee)(E.next());
if( emp.getSalary() > S.getSalary() )
{
v.add( E );
}
}
return( v.iterator() );
}



Similar code no doubt exists in a number of production programs written in Java. Note that the above program can be written in a form of pseudocode that looks like the following:



public Iterator getEmps( Iterator E , Supervisor S )
{
return( select Emp from Emp in E where ( (Employee) Emp ).getSalary() > S.getSalary() );
}



The above code has some SQL-like syntax, but the semantics is different. The above expression iterates over an Iterator, whereas typical SQL iterates over relations. More importantly, the above expression suggests a mechanism for expressing JFC-like iteration patterns through declarations (as opposed to imperative while loops). This "select" semantics provides an alternative to operators from intensional programming such as “fby”, “prev”, “next”, and “at”. The "select" semantics creates declarations that map readily to iterative code, whereas typical intensional language compilation requires an optimization process to remove recursive elements of the intensional declarations. A typical select expression in JUndo looks like the following:


pair[ IteratorFactory ] empFac = select e
from e : Employees , s : Supervisors
into now
where ( [Employee] e ).getSalary() > ( [Supervisor] s ).getSalary();



In the above expression, which finds all employees who make more than some supervisor, "Employees" and "Supervisors" are of type IteratorFactory, where IteratorFactory is an interface with a single method called iterator() that returns an Iterator. For instance, the java.util.Vector class in the Java language could easily by turned into a Java iterator factory because it already has an appropriate iterator() method. Several other classes in JCF have similar iterator() methods. In the JUndo syntax, Iterator and IteratorFactory can be defined as follows:


public interface Iterator
{
public pair[ boolean ] hasNext();
public pair[ Object ] next();
}

public interface IteratorFactory
{
public pair[ Iterator ] iterator();
}



Referential Transparency in JUndo

Functions in pure functional languages obey the concept of referential transparency defined as "the execution of a function always produces the same result when given the same parameters" (7). A form of referential transparency also holds for JUndo methods. Consider the following call to a JUndo instance method:


[ myObj , myMilieu ].myMethod( a , b , c , d )


In a typical implementation of a JUndo compiler, myObj would be curried into a this parameter in the object-code version of the method call (much as is currently done in most C++/Java/C compilers). The milieu myMilieu would also be curried into a this_milieu parameter in the object-code version of the method. In JUndo defining referential transparency requires the inclusion of the "hidden" parameters that are typically curried into the object code. For instance, the instance method myMethod above always returns the same result (to within the ability to observe differences using the language) as long as the equivalents of a, b, c, d, myObj, and myMilieu remain the same. This includes functions that return milieu describing modifications to objects and functions that return milieu describing the creation of new objects. The definition of referential transparency for a JUndo class method is similar, but only this_milieu is curried (a this parameter isn't curried because it is an error for class methods to use a this reference).


Conclusion

Multi-level undo can be implemented in JUndo by creating a class library that associates a milieu with each important point in the undo/redo timeline. Details have been omitted in order to fit SIGPLAN's length limitation. To conclude, the reasons for motivating the JUndo language have been expressed, and some novel features of the language have been described. There are a number of other elements in the language, such as arrays and let expressions, that are not described in this paper. For additional explanation, please see the following web site: http://verdantium.blogspot.com

References

1. W. W. Wadge, and E. A. Ashcroft, Lucid, the Dataflow Programming Language, Academic Press, New York, NY, 1985.

2. P. J. Landin, ‘The Next 700 Programming Languages’ CACM, 9, 157-166 (1966).

3. T. Faustini, Visual Java, Computer Software, (unpublished).

4. K. Arnold, and J. Gosling, The Java Programming Language, Addison-Wesley, Menlo Park, CA, 1996.

5. B. Stroustrup, and M. A. Ellis, The Annotated C++ Reference Manual, Addison-Wesley, Menlo Park, CA, 1990.

6 J. Corney, and T. Lim, 3D Programming with ACIS, Saxe-Coburg, Stirling, UK, 2001.

7. R. W. Sebesta, Concepts of Programming Languages, Seventh Edition, Addison-Wesley, San Francisco, CA, 2005.

8 Edwards, K., Igarashi, T., LaMarca, A., and Mynatt, E. D. A Temporal Model for Multi-Level Undo and Redo. In Annual ACM Symposium on User Interface Software and Technology, November 2000, pp. 3140. http://citeseer.csail.mit.edu/edwards00temporal.html

9 E. Gamma, R. Helm, R. Johnson, and J. Vlissides, "Design Patterns", Addison-Wesley, Menlo Park, CA, 1995.

10 Green, Thornton, "Verdantium-- Towards a Java-Enabled Compound-Document Model", Poster Session, OOPSLA 2000 Conference, ACM, October 15-19, 2000, Minneapolis, Minnesota.

Monday, August 6, 2007

Verdantium version 070806

This is a bug-fix for yesterday's version (070805). This version is more stable, but not yet stable. More of the undo functionality in DrawApp is working in this version. There is still much to do on this, particularly for supporting persistence. However, a surprising amount of the multi-level undo support is working in this version.

Changed Verdantium description on SourceForge

I keep noticing a trend where a lot of people download Verdantium, but few people download the underlying framework projects. For instance there were nine Verdantium downloads within a short period after the latest post, but there were very few downloads of Meta or Jundo Runtime. So I suspect that the current Verdantium downloads aren't producing successfully executing builds. One needs to download the new versions of the other projects in order to build the new Verdantium version. To help this, I've tried to make it easier for people to notice this blog post. The original Verdantium description read as follows:


Verdantium is an OpenDoc-like compound-document framework, and an open-source alternative to frameworks underlying OpenOffice, StarOffice, Corel Office, and Microsoft Office. Verdantium is written in a combination of JUndo, Java JFC/Swing, and Java-2D.


To keep the new description in the in the 254 character limit I changed it to:


Verdantium is an OpenDoc-like compound-document framework, and an open-source alternative to frameworks underlying OpenOffice, StarOffice, Corel Office, and Microsoft Office. Written in JUndo / Java JFC/Swing/Java-2D See http://verdantium.blogspot.com/

Sunday, August 5, 2007

More about the 0805 (i.e. August 5) Verdantium / JUndo Update

Now that the August 5 update is fully posted I wanted to log a little about this particular version. The new version is an unstable test version with an expanded undo capability. I've been coding on this version for a while now, and now that I have got something that is nominally working I wanted to archive it to sourceforge before it got accidentally deleted by something like a hard disk crash (stranger things have happened with my hard disk lately).

So this is a Verdantium release that is partially an advance, partially untested, and partially outright broken. The nexus of the Verdantium changes is the verdantium.standard.DrawApp class. This class now has a partial implementation of multi-level undo. Some of it is actually working quite well. You can add a series of lines to the DrawApp, and then undo them one by one. Other aspects of the implementation, especially DrawApp persistence, are completely broken while I finish writing the code.

As the name implies, "JUndo" is is a multi-level undo language for Java. Hence, it is spelled with a "J" for Java followed "Undo" for undo. JUndo is actually more than that, but undo is the primary practical issue that the language resolves. JUndo makes it feasible to use undo patterns that are difficult to implement in ordinary Java. Many typical systems use one of two patterns: either store a memento on every operation that encapsulates a copy of the entire data state, or create an inverse command for every command. The first is very computationally expensive and memory-consuming for programs storing large amounts of data (imagine making a copy of the entire data store every time you update a field), and the second tends to require the creation of very sophisticated command objects to undo operations such as deletions or sort operations (e.g. a command to sort a list requires an undo command that will "unsort" a list-- think about that the next time you bubble sort). JUndo solves these problems by providing objects which support a temporal model of undo. In Verdantium / JUndo undo, inverse commands aren't needed. The developer simply never needs to create an inverse command. Moreover, the JUndo system is very efficient at only storing changes between states, rather than generating memento patterns describing the entire state of a system.

Some of this can be seen in the new version of DrawApp. Some very complex operations are performed on the rendering primitives in DrawApp, and yet there is no need to create inverse commands. The elimination of inverse commands potentially makes the developer much more prroductive, and potentially makes the resulting system much more self-consistent. Inverse commands sometimes have bugs, and these bugs can produce inconsistent data states and systems that are not self-consistent. JUndo implementations avoid these inconsistencies. Further, operations tend to be fast because only changes to objects are stored.

As an example, primitives can be added to the DrawApp rendering list without the need to produce inverse commands to remove those items from the rendering list. Instead, the undo system simply remembers what the list looked like in its previous state and automatically takes the list back if the user performs an undo operation. This should become very impressive as the new implementation of DrawApp is fully developed. Developers can take advantage of these new extensions to the undo system in their own components.

New Verdantium, JUndo, and Meta Release 070805

I just put a new release of Verdantium, and JUndo on sourceforge. To get a full working Verdantium build, you need to download code from the following sourceforge projects:



http://sourceforge.net/projects/verdantium/

http://sourceforge.net/projects/jundoruntime/

http://sourceforge.net/projects/meta/


There is a new build requirement in this build: The umeta package from the JUndo Runtime project is now a required library for Verdantium. Also, to build the ".JUndo" files into Java source, one needs the following project:


http://sourceforge.net/projects/jundo/


I've made this blog the project page for all of the above sourceforge projects on the theory that if you are interested in one of them then you should probably be interested in the others. Verdantium requires JUndo and Meta in order to run. Understanding JUndo is useful for writing verdantium components, particularly components that support multi-level undo. Enhancements to JUndo are made just to support Verdantium. If one is interested in developing for Verdantium then one would probably also be interested in JUndo.

Similarly, if one is interested in JUndo then one should probably be interested in Verdantium. Programming languages have to answer the question "what is this [language] good for?" Otherwise, there is no point in developing a new language. Verdantium and its multi-level undo system gives one a context for the kinds of problems that JUndo was created to solve. That is to say, Verdantium ties JUndo to a practical application.

I have been looking at download statistics, and I see many downloads for Verdantium, but far fewer downloads for JUndo and Meta. This seems strange given that one needs the latter in order to run the former. I wonder if people are actually getting workable systems if they are downloading Verdantium, but not JUndo or Meta. If you download Verdantium, then please download the other projects.