A plan for learning clojure

I had printed out the list of functions and macros in the Clojure API page, and it filled out two A4 pages. Where to start though? I walked the entire clojure and clojure contrib directory and counted the number of function calls. Here are the top stats.

sym	count	len
clojure.core/list	3872	17
quote	2749	5
defn	1757	4
clojure.core/seq	1481	16
clojure.core/concat	1480	19
=	1074	1
let	1042	3
is	885	2
.	836	1
if	826	2
defmethod	431	9
def	407	3
complex	377	7
defn-	376	5
fn	356	2
first	346	5
defmacro	298	8
clojure.core/apply	264	18
deftest	257	7
str	252	3
when	244	4
imaginary	238	9
recur	237	5
apply	229	5
instance?	220	9
nil	217	3
and	214	3
next	208	4
cl-format	206	9
fn*	197	3
ns	194	2
map	193	3
:use	187	4
list	184	4
1	181	1
count	178	5
+	169	1
seq	167	3
reduce	165	6
are	148	3
cons	143	4
println	141	7
or	141	2
not	135	3
loop	133	4
thrown?	127	7
*	127	1
conj	125	4
print	124	5
nth	124	3
-	116	1
doseq	114	5

Now, I have a study-plan.

Incidentally, waterfront IDE is quite nice, particularly because I don’t have to learn Emacs key-bindings. There are some moments when it barfs and prints out hashmaps incorrectly, but I enjoyed working in a REPL environment.

JavaFX experiment

I was having a lot of problems getting the simplest test case below to run without throwing an odd exception:

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.ext.swing.SwingTextField;
import javafx.ext.swing.SwingButton;

Stage {
    title : "MyApp"
    scene: Scene {
        width: 200
        height: 200
        content: [
            VBox{
                content:
                [
                SwingTextField {
                columns: 10
                text: "TextField"
                editable: true
                },
                SwingButton {
                text: "Button"
                action: function() {  }
                }]
            }

        ]
    }
}

SwingTextField barfs like this:

Exception in thread "AWT-EventQueue-1" java.lang.IllegalArgumentException: Zero length string passed to TextLayout constructor.
        at java.awt.font.TextLayout.(TextLayout.java:364)
        at sun.font.FontDesignMetrics.charsWidth(FontDesignMetrics.java:487)
        at javax.swing.text.Utilities.getTabbedTextWidth(Utilities.java:262)
        at javax.swing.text.Utilities.getTabbedTextWidth(Utilities.java:191)
        at javax.swing.text.PlainView.modelToView(PlainView.java:335)
        at javax.swing.text.FieldView.modelToView(FieldView.java:248)
        at javax.swing.plaf.basic.BasicTextUI$RootView.modelToView(BasicTextUI.java:1496)
        at javax.swing.plaf.basic.BasicTextUI.modelToView(BasicTextUI.java:1034)
        at javax.swing.text.DefaultCaret.paint(DefaultCaret.java:600)
        at javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:730)
        at javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:868)
        at javax.swing.plaf.basic.BasicTextUI.update(BasicTextUI.java:847)
        at javax.swing.JComponent.paintComponent(JComponent.java:758)
        at javafx.ext.swing.JTextFieldImpl.paintComponent(JTextFieldImpl.java:77)
        at javax.swing.JComponent.paint(JComponent.java:1022)
        at javax.swing.JComponent.paintChildren(JComponent.java:859)
        at javax.swing.JComponent.paint(JComponent.java:1031)
        at com.sun.embeddedswing.EmbeddedPeer.paint(EmbeddedPeer.java:135)
        at com.sun.scenario.scenegraph.SGComponent.paint(SGComponent.java:121)
        at com.sun.scenario.scenegraph.SGLeaf.render(SGLeaf.java:179)
        at com.sun.scenario.scenegraph.SGWrapper.render(SGWrapper.java:122)
        at com.sun.scenario.scenegraph.SGGroup.render(SGGroup.java:222)
        at com.sun.scenario.scenegraph.SGWrapper.render(SGWrapper.java:122)
        at com.sun.scenario.scenegraph.SGGroup.render(SGGroup.java:222)
        at com.sun.scenario.scenegraph.SGGroup.render(SGGroup.java:222)
        at com.sun.scenario.scenegraph.JSGPanel.paintComponent(JSGPanel.java:582)
        at javax.swing.JComponent.paint(JComponent.java:1022)
        at javax.swing.JComponent.paintChildren(JComponent.java:859)
        at javax.swing.JComponent.paint(JComponent.java:1031)
        at javax.swing.JLayeredPane.paint(JLayeredPane.java:564)
        at javax.swing.JComponent.paintChildren(JComponent.java:859)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5111)
        at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1386)
        at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1317)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1132)
        at javax.swing.JComponent.paint(JComponent.java:1008)
        at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:21)
        at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:60)
        at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:97)
        at java.awt.Container.paint(Container.java:1797)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:738)
        at javax.swing.RepaintManager.seqPaintDirtyRegions(RepaintManager.java:667)
        at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:128)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
        at com.sun.embeddedswing.EmbeddedEventQueue.dispatchEvent(EmbeddedEventQueue.java:369)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

Running javafx with the verbose switch pointed the fault out

javafx -verbose:class test
:
:
[Loaded java.awt.Container$EventTargetFilter from c:Progra~1Javajdk1.6.0jrelibrt.jar]
:

I was running an old version of the JDK!
Unsetting the JAVA_HOME resolved the problem.
I hope this helps somebody.

JavaFX Custom Cursors

Setting custom cursors with JavaFx is relatively straightforward, but for one little catch. Your image has to be 32×32. If you want a 16×16 icon, simply leave the rest of the image transparent.

import java.awt.Toolkit;
import javafx.scene.Cursor;
import javafx.scene.image.Image;

public class ColorChooser extends Cursor
{
    public override function impl_getAWTCursor(): java.awt.Cursor {

        def url = "{__DIR__}eyedropper.png";

        var toolkit = Toolkit.getDefaultToolkit();

        var image = Image{width:32 height:32 url:url}.bufferedImage;
        var hotspot = new java.awt.Point(0,15);
        var cursor = toolkit.createCustomCursor(image, hotspot, "colorpicker");
        return cursor;
    }
}

public def ColorChooserCursor=ColorChooser{};

public function run()
{
    javafx.scene.shape.Rectangle
    {
        x:5 y:5
        width:200 height:200
        cursor:ColorChooserCursor
    }
}

Tags:

JavaFX Introspection

Just sharing some code snippets for deserialization of JavaFX objects.

function getValueType(obj:Object,name:String):String
{
    var context:FXLocal.Context=FXLocal.getContext();
    var objectValue:FXLocal.ObjectValue = new FXLocal.ObjectValue(obj,context);
    var cls:FXClassType = objectValue.getClassType();
    var varType:FXType = cls.getVariable(name).getType();
    println("{name} {varType}");
    if (varType instanceof FXSequenceType)
    {
        return "array";
    } else if (varType instanceof FXClassType) {
        return "element";
    } else {
        return "value";
    }
}

Thanks to James Weaver for tips on JavaFX Reflection API

JavaFX binding in sequences

I had a Group of circles, i.e.

var circles:Circle[];
var group:Group = Group { content: [circles] };

strangely, I couldn’t get newly inserted circles to render.

It turns out that you have to bind group.content to ensure that changes in circles are reflected in group.content.

Here’s a test routine.

import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.stage.*;

var lines = for (i in [1..10])
    Line {startX:i*30 startY:20 endX:i*20 endY:500};

var circles = for (i in [1..10])
    Circle {centerX:i*30 centerY:50 radius:20};

Stage
{
    scene: Scene
    {
        content: Group
        {
            content: // bind
            [

                Rectangle {fill:Color.YELLOW width:800 height:500}
                circles,
                lines,

            ]

            onMouseClicked: function(e)
            {
                println('clicked');
                insert Circle {fill:Color.RED centerX:e.x centerY:e.y radius:20} into circles;
            }

        }

    }
}

Uncomment the //bind and observe the difference.

Applet for Submitting Screenshot

Submitting screenshots through the web takes several steps more than it ought to. Firstly we have to paste it into mspaint.exe, save it to disk, only to then fiddle around with the File upload to look for the file again.

Another way to do it is via a signed applet. Unfortunately, the signed applet is unable to cooperate with the rest of the HTML form to submit multipart posts.

The next best thing is to send the screenshot to a hidden field with a base64 encoded image.

Download signed jar with sources SImageUploadApplet.jar

Here’s a proof of concept:

image upload applet

Download signed jar with sources SImageUploadApplet.jar

It’s 2009, perhaps HTML should have a rich text area that can submit inlined images.

Database Patterns realized with AribaWeb

Take a look at aribaweb.org (viaTheServerSide).

AribaWeb is a 4GL RAD for web applications running on a Java stack.

It uses an approach described in data dictionaries as a database pattern to generate metadata-driven UI.

The Ariba toolset seems reasonably mature from the screencasts, although one has to be wary because a lot of the AJAX work appears to be relatively new.

I’m watching the MetaUI screencast now, and the bubble style error messages on fields is quite cool. However, cooler still is the use of CSS-like language to mark up how fields are presented. This reduces impedance mismatch between binding data to controls, instead turns data into its representation.

Custom validation rules is specfied using a groovy string. I’m not sure if this is translated into Javascript on the client-side. The Meta UI specification decoupled from HTML (layout is in named zones), and there is no reason why this couldn’t be rendered in a RIA.

Actions in UI on a POJO is declared via an annotation (similar to Naked Objects). However, the actions seem to be more restrictive in the sense that the methods must not take any arguments.

e.g.

@Action(message="Account Suspended")
@Visible("! $object.isSuspended")
void suspendAccount() {
...
}

Overall, AribaWeb looks very polished. I haven’t had a look at the underlying libraries used1, but I look forward to delve into it further.

Footnotes

1There was a mention of JPA and Hibernate. (Is the display layer JSF?)

JavaFX redux

Having spent a few weeks experimenting with JavaFX, and creating several examples, here is an assessment of whether JavaFX succeeds in it’s objective of being a graphics DSL. Bear in mind that I am evaluating it in terms of it’s ease in being a graphics DSL – if it makes my life easier, it succeeds. Where it makes my life harder than developing web apps – it fails.

On with the list.

Wins

  • bind keyword – it took a while, but finally concepts from sloppy tools like Excel is making it’s way into mainstream programming languages. Programmers should never have to do the work that a computer can do just as well.
  • First class support for animations The language simplifies the process of creating keyframe-styled animations, without having to launch background threads, worry about EDT and having to write callback code for timers.
  • Object initializer syntax Using keyword-style arguments suits objects which has tonnes of properties
  • effect property in Nodes makes it straightforward to add “bling” to a project without having to rearrange program layout
  • strong support for functional-style programming List comprehensions, filter, map. Built into the language.

Losses

  • Javaesque layouts, not Webesque – containers are emphasised over styles. This is not going to win any points with the semantic crowd.
  • Difficulty in adding extension points – I would have favoured seeing C# static extension methods in the language. It would have made adding behaviors easier. For instance, centering a piece of text takes more effort than it should, and once done it could not be easily refactored and added to other elements. I regard this as a wart in a DSL that aims to support animators.
  • Difficulty in adding behaviors – adding behaviors like “clickable”, “hoverable”, “draggable” requries programmatic intervention, rather than being able to declaratively do this. This is due to the absence of extension points above, and the absence of namespacing from the YAML syntax. XML-style syntax would have been kinder to these kind of mashups.
  • The DSL may be suited for laying out standard blocky objects, but (I was working with Vim and) it was hard to lay things out by hand. One still needs to fall back on a graphic editor to create most of the resources.
  • The story on accessibility is still unclear – granted that JavaFX is a DSL for graphics and animations, however, it’s target is to be a platform for developing applications. Without a clear accessibility story, JavaFX will never see the doors of a government application, or a public-facing application of large corporations.
  • event handlers – there is only one for each event. I couldn’t figure out why. onclick=”…” is so 1997.

Recommendations

  • Tools support is essential The language compiler project should make the abstract syntax trees available so that third parties can easily develop tools to parse the language. Currently, it is a one-way conversion from Adobe/SVG to FXD. Syntax sugar in the Timeline, duration may be cutesy, but we need parsers please.
  • Extend language to make it easy for developers to add custom attributes and behaviors to graphical nodes. The OpenJFX developers should wrap Centering layout code for each graphical shape to see how weak JavaFX is in this area.
  • More support to attract web developers – the people who are writing the specs come from a Java development background, and it shows. The JavaFX language team needs a few web developers on the advisory board to make it easy to attract this particular constituent.
  • more interfaces and less inheritance – when writing layout code, I’m frequently stymied by containers like scene and stage which do not have the same base classes, making it hard to measure width and height.

JavaFX TextAlignment Gotcha

Here is a minimal test case illustrating how exasperating the default JavaFX Text node can be, especially when aligning text.

You’d be surprised to note that both pieces of text below are aligned using TextAlignment.CENTER.

Problems With TextAlign in JavaFX

import javafx.scene.text.*;
import javafx.scene.layout.*;

VBox
{
    translateY:10
    content:
    [
    Text {
        textAlignment:TextAlignment.CENTER
        content: "A New World"
    }
    ,
    Text {
        textAlignment:TextAlignment.CENTER
        content: "A Mighty PubnwithnAbsolutely No Bitter Beer"
    }
    ]
}

Apparently, the state of the art work-around is to calculate the mid-point using myTextNode.boundsInLocal.width, and then position using translateX.

Not good enough, Sun. Not good enough.

Here’s the worked around code

import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.layout.*;

var scene:Scene;
scene=Scene
{
    content:
    {
        VBox
        {
            translateY:10
            content:
            [
            Text {
                id: "label1"
                translateX: bind (scene.width-scene.lookup("label1").boundsInLocal.width)/2
                textAlignment:TextAlignment.CENTER
                content: "A New World"
            },
            Text {
                id: "label2"
                translateX: bind (scene.width-scene.lookup("label2").boundsInLocal.width)/2
                textAlignment:TextAlignment.CENTER
                content: "A Mighty PubnwithnAbsolutely No Bitter Beer"
            },
            ]
        }
    }
}