I once took a job that Geert Bevin had left a week or so before. I was blown away at the code quality and advanced topics of the code he’d left behind. That was late 1999 and my introduction to Inversion of Control and Perforce. Since then, he has remained one of the people that cyclically reminds me I’ve more things to learn in software development. Rife is his advanced web-framework and within it, he’s made a simple Java-based build technology Bld that you could use instead of Maven, Gradle and others. Like all good reusable things, he’s eeked it out of a single use: it is Rife2’s build system.

Bld’s example script

package com.example;

import rife.bld.Project;
import java.util.List;
import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.*;

public class MyappBuild extends Project {
    public MyappBuild() {
        pkg = "com.example";
        name = "Myapp";
        mainClass = "com.example.MyappMain";
        version = version(0,1,0);

        downloadSources = true;
        repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
        scope(test)
            .include(dependency("org.junit.jupiter",
                                "junit-jupiter",
                                version(5,9,2)))
            .include(dependency("org.junit.platform",
                                "junit-platform-console-standalone",
                                version(1,9,2)));
    }

    public static void main(String[] args) {
        new MyappBuild().start(args);
    }
}

I like pseudo-declarative DSLs. To make a few that I have specifically liked:

  • Groovy’s one (originally called Builder I think)
  • QML - QT’s markup language that coulda been a huge thing (has JavaScript as the woven-in non-declarative language)
  • Kotlin’s one (you can see it used well in TornadoFX
  • Ruby has one too - I forget if it has a name
  • Flutter (has Dart as the woven-in non-declarative language)

Pseudo-declarative means it looks superficially that scripts are declarative, but there is optionally support for if conditions, for loops and regular statements … even if you’d attempt to not use them.

Plain Java does not. You can get close with initializer tricks though - see JMock2 and test frameworks Cuppa and Oleaster. Hacky but not totally ugly.

A DSL version of that Bld example

Anyway, I thought I would have a quick go at turning Geert’s Bld script into something that approximated the Pseudo declarative grammar I am drawn to:

import java.util.List;

public class Main {
    public static void main(String[] args) {
        new Project() 
            );
        }}.start(args);
    }

    private static class Version {
        private final int i, i1, i2;

        public Version(int i, int i1, int i2) {
            this.i = i;
            this.i1 = i1;
            this.i2 = i2;
        }
    }

    private static class Scope {

        public Scope(String scopeName) {
            // todo
        }

        public void include(Dependency dependency) {
            // todo
        }
    }

    private static class Dependency {

        public Dependency(String scopeName, String s1, Version version) {
        }

    }

    private static class Project {

        static final String MAVEN_CENTRAL = "MAVEN_CENTRAL";
        static final String RIFE2_RELEASES = "RIFE2_RELEASES";
        static final String test = "scope_test";


        protected String pkg, name, mainClass;
        protected Version version;
        protected boolean downloadSources;
        protected List<String> repositories;


        public void start(String[] args) {
            // todo
        }

        protected Version version(int i, int i1, int i2) {
            return new Version(i, i1, i2);
        }

        protected void scope(Scope scope) {
            // todo: register that scope with the project somehow
        }

        protected Dependency dependency(String s, String s1, Version version) {
            return new Dependency(s, s1, version);
        }

    }
}

It doesn’t do anything as bld.jar was not used for the experiment, and I’ve probably broken compatibility with it. The bit in the main() method is what you should focus on.

More syntactic sugar for Java

This got me thinking that more sugar could be applied to this section:

scope(
    new Scope(test) 
);

Yup it’s an accident here that it is Bld’s Scope class that’s in the example, and that programmatic scope is focus of conversation.

Does this make it clearer?

skope(
    new Skope(test) 
);

What if a future JEP could allow for:

skope("test") ;

It would need some factory-method-ish clue in the method declaration:

// in Project class
@FactoryMethodIsh
protected Skope skope(String skopeText) {
    Skope skope = new Skope(skopeText);
    project.addSkope(skope); // say there was an addSkope member (not shown in code snippets previously)
    return skope; // AND allow for ongoing initializer trick.
}

The compiler would make the inline bytecode equivalent of this:

// as many of these as there were uses of skope(..)
{ 
    Skope skope123 = new new Skope(skopeText) ;
    project.addSkope(skope123); 
    // skope123 would be available to following statements IF there were an assignment for the skope(..) use. 
}

skope123, is unique to scope and contrived by the compiler. Could as easily be skope127, etc.

Talking of JEPs one for main-method syntactic sugar is years late versus C# getting it.



Published

May 14th, 2023
Reads: